Bonjour,
Récemment s'est posé la question de convertir une image grise en 2
niveaux de noir et blanc. Une des solutions consiste à traiter l'image
avec une boucle.
Le pb est que si l'image est grosse (2 mégas pixels dans l'exemple
ci-après), le traitement est long (environ 20 secs sur un PC moyen).
Sachant que la boucle est un bête test du premier octet de chaque groupe
de trois octets, suivis d'une concaténation de chaîne, quelqu'un
connaît-il un moyen d'aller plus vite ?
Merci
jm
# -*- coding: iso-8859-1 -*-
from array import *
print 'début'
grisClair= chr(240)*3
grisFonce= chr(10)*3
data1= array('c',(grisClair+grisFonce)*10**6) # crée un array contenant
un buffer de 2 millions de pixels RVB gris
data2= ''
blanc= chr(255)*3
noir= chr(0)*3
# boucle sur chaque groupe de 3 octets du buffer
for pixind in range(0,len(data1),3):
if ord(data1[pixind]) < 128:
data2=data2+noir
else:
data2=data2+blanc
# data2 est un string contenant un buffer de 2 millions de pixels blancs
ou noirs
print 'fin'
je propose pour illustrer les 4 codes suivants et leur bench respectifs def test4(): return [choice[o(pix) < 128] for pix in data1[::3]] Il faut juste ajouter le join dans test4() :
return ''.join([choice[o(pix) < 128] for pix in data1[::3]])
il y a tout de meme une sacré echelle de différence non ?? ...et c'est effectivement plus que satisfaisant.
J'ai intégré ce code dans l'appli que j'ai utilisé pour faire le test avec wx, et les images sont affichées maintenant dans un temps tout à fait acceptable compte tenu de leur taille (qlques secondes). De plus, les solutions évoquées m'ouvrent des horizons pour d'autres optimisations. Si quelqu'un est intéressé par un code complet et autonome avec wx pour transformer une série d'images, il n'a qu'à demander. Merci pour toutes les réponses. A+ jm PS: autre solution évoquée par un ami: le regexp ; mais est-ce vraiment pythonien ?
Eric Deveaud wrote:
je propose pour illustrer les 4 codes suivants et leur bench respectifs
def test4():
return [choice[o(pix) < 128] for pix in data1[::3]]
Il faut juste ajouter le join dans test4() :
return ''.join([choice[o(pix) < 128] for pix in data1[::3]])
il y a tout de meme une sacré echelle de différence non ??
...et c'est effectivement plus que satisfaisant.
J'ai intégré ce code dans l'appli que j'ai utilisé pour faire le test
avec wx, et les images sont affichées maintenant dans un temps tout à
fait acceptable compte tenu de leur taille (qlques secondes).
De plus, les solutions évoquées m'ouvrent des horizons pour d'autres
optimisations.
Si quelqu'un est intéressé par un code complet et autonome avec wx pour
transformer une série d'images, il n'a qu'à demander.
Merci pour toutes les réponses.
A+
jm
PS: autre solution évoquée par un ami: le regexp ; mais est-ce vraiment
pythonien ?
je propose pour illustrer les 4 codes suivants et leur bench respectifs def test4(): return [choice[o(pix) < 128] for pix in data1[::3]] Il faut juste ajouter le join dans test4() :
return ''.join([choice[o(pix) < 128] for pix in data1[::3]])
il y a tout de meme une sacré echelle de différence non ?? ...et c'est effectivement plus que satisfaisant.
J'ai intégré ce code dans l'appli que j'ai utilisé pour faire le test avec wx, et les images sont affichées maintenant dans un temps tout à fait acceptable compte tenu de leur taille (qlques secondes). De plus, les solutions évoquées m'ouvrent des horizons pour d'autres optimisations. Si quelqu'un est intéressé par un code complet et autonome avec wx pour transformer une série d'images, il n'a qu'à demander. Merci pour toutes les réponses. A+ jm PS: autre solution évoquée par un ami: le regexp ; mais est-ce vraiment pythonien ?
Eric Deveaud
Laurent Pointal wrote:
Je n'ai pas le même niveau de différence. Ton script, en repassant en 10**6 pour pouvoir comparer avec les tests que j'ai fait un peu avant:
C:dev>python grisailles.py test 1 9.383566 test 2 1.359730 test 3 1.264727 test 4 0.786419
avec 10^6 j'obtiens ceci
hebus:check/work_dir > python test.py test 1 184.710757 test 2 3.726266 test 3 3.478191 test 4 2.855085
hebus:check/work_dir > python2.3 test.py test 1 185.339335 test 2 3.666680 test 3 3.422132 test 4 2.847318
ta machine est bougrement plus rapide que la miene ;-))
Eric
Laurent Pointal wrote:
Je n'ai pas le même niveau de différence.
Ton script, en repassant en 10**6 pour pouvoir comparer avec les tests
que j'ai fait un peu avant:
C:dev>python grisailles.py
test 1 9.383566
test 2 1.359730
test 3 1.264727
test 4 0.786419
avec 10^6 j'obtiens ceci
hebus:check/work_dir > python test.py
test 1 184.710757
test 2 3.726266
test 3 3.478191
test 4 2.855085
hebus:check/work_dir > python2.3 test.py
test 1 185.339335
test 2 3.666680
test 3 3.422132
test 4 2.847318
ta machine est bougrement plus rapide que la miene ;-))
Je n'ai pas le même niveau de différence. Ton script, en repassant en 10**6 pour pouvoir comparer avec les tests que j'ai fait un peu avant:
C:dev>python grisailles.py test 1 9.383566 test 2 1.359730 test 3 1.264727 test 4 0.786419
avec 10^6 j'obtiens ceci
hebus:check/work_dir > python test.py test 1 184.710757 test 2 3.726266 test 3 3.478191 test 4 2.855085
hebus:check/work_dir > python2.3 test.py test 1 185.339335 test 2 3.666680 test 3 3.422132 test 4 2.847318
ta machine est bougrement plus rapide que la miene ;-))
Eric
Eric Deveaud
jean-michel bain-cornu wrote:
Eric Deveaud wrote:
je propose pour illustrer les 4 codes suivants et leur bench respectifs def test4(): return [choice[o(pix) < 128] for pix in data1[::3]] Il faut juste ajouter le join dans test4() :
return ''.join([choice[o(pix) < 128] for pix in data1[::3]])
ooooops
PS: autre solution évoquée par un ami: le regexp ; mais est-ce vraiment pythonien ?
dans la vraie vie quand tu comences a chercher a optmiser, j'aurais tendance a dire que les pythonisme tu t'en fout un peu ;-) dans le pire des cas tu fini par fiare un module en C que tu linke avec ton code python (cf swig)
petite questions comment acquiers tu les valeurs de tes images ? lecture classique / mmap ?? il doit y avoir encore des pouiemmes a grapiller de ce cote
Eric
jean-michel bain-cornu wrote:
Eric Deveaud wrote:
je propose pour illustrer les 4 codes suivants et leur bench respectifs
def test4():
return [choice[o(pix) < 128] for pix in data1[::3]]
Il faut juste ajouter le join dans test4() :
return ''.join([choice[o(pix) < 128] for pix in data1[::3]])
ooooops
PS: autre solution évoquée par un ami: le regexp ; mais est-ce vraiment
pythonien ?
dans la vraie vie quand tu comences a chercher a optmiser,
j'aurais tendance a dire que les pythonisme tu t'en fout un peu ;-)
dans le pire des cas tu fini par fiare un module en C que tu linke avec ton
code python (cf swig)
petite questions comment acquiers tu les valeurs de tes images ?
lecture classique / mmap ?? il doit y avoir encore des pouiemmes a grapiller de
ce cote
je propose pour illustrer les 4 codes suivants et leur bench respectifs def test4(): return [choice[o(pix) < 128] for pix in data1[::3]] Il faut juste ajouter le join dans test4() :
return ''.join([choice[o(pix) < 128] for pix in data1[::3]])
ooooops
PS: autre solution évoquée par un ami: le regexp ; mais est-ce vraiment pythonien ?
dans la vraie vie quand tu comences a chercher a optmiser, j'aurais tendance a dire que les pythonisme tu t'en fout un peu ;-) dans le pire des cas tu fini par fiare un module en C que tu linke avec ton code python (cf swig)
petite questions comment acquiers tu les valeurs de tes images ? lecture classique / mmap ?? il doit y avoir encore des pouiemmes a grapiller de ce cote
Eric
jean-michel bain-cornu
Eric Deveaud wrote:
petite questions comment acquiers tu les valeurs de tes images ? lecture classique / mmap ?? il doit y avoir encore des pouiemmes a grapiller de ce cote Pas vraiment je pense.
C'est fait avec la classe Image de wx : img= wx.Image('photo.jpg',wx.BITMAP_TYPE_JPEG) data1= img.GetData() # obtient un array data1 ...passage en blanc/noir... img.SetData(data2) # attends un data2 string bmp= wx.BitmapFromImage(img) stbmp= wx.StaticBitmap(parent,wx.ID_ANY,bmp) ..etc.. ce qui fait que je n'ai pas trop la main sur ce qui se fait et qui est d'ailleurs très rapide (sans traitement, l'affichage des images est instantané, même avec un processeur en bois). A+ jm
Eric Deveaud wrote:
petite questions comment acquiers tu les valeurs de tes images ?
lecture classique / mmap ?? il doit y avoir encore des pouiemmes a grapiller de
ce cote
Pas vraiment je pense.
C'est fait avec la classe Image de wx :
img= wx.Image('photo.jpg',wx.BITMAP_TYPE_JPEG)
data1= img.GetData() # obtient un array data1
...passage en blanc/noir...
img.SetData(data2) # attends un data2 string
bmp= wx.BitmapFromImage(img)
stbmp= wx.StaticBitmap(parent,wx.ID_ANY,bmp)
..etc..
ce qui fait que je n'ai pas trop la main sur ce qui se fait et qui est
d'ailleurs très rapide (sans traitement, l'affichage des images est
instantané, même avec un processeur en bois).
A+
jm
petite questions comment acquiers tu les valeurs de tes images ? lecture classique / mmap ?? il doit y avoir encore des pouiemmes a grapiller de ce cote Pas vraiment je pense.
C'est fait avec la classe Image de wx : img= wx.Image('photo.jpg',wx.BITMAP_TYPE_JPEG) data1= img.GetData() # obtient un array data1 ...passage en blanc/noir... img.SetData(data2) # attends un data2 string bmp= wx.BitmapFromImage(img) stbmp= wx.StaticBitmap(parent,wx.ID_ANY,bmp) ..etc.. ce qui fait que je n'ai pas trop la main sur ce qui se fait et qui est d'ailleurs très rapide (sans traitement, l'affichage des images est instantané, même avec un processeur en bois). A+ jm
aaa
encore un peu plus rapide en remplacant la fin de test4():
choice = ( blanc, noir) # astuce pour eviter le look ahead ... maintenant inutile carac=chr(128) return [choice[pix < carac] for pix in data1[::3]]
on evite ainsi le ord()....
Eric2
encore un peu plus rapide en remplacant la fin de test4():
choice = ( blanc, noir)
# astuce pour eviter le look ahead ... maintenant inutile
carac=chr(128)
return [choice[pix < carac] for pix in data1[::3]]
encore un peu plus rapide en remplacant la fin de test4():
choice = ( blanc, noir) # astuce pour eviter le look ahead ... maintenant inutile carac=chr(128) return [choice[pix < carac] for pix in data1[::3]]
on evite ainsi le ord()....
Eric2 Et ça rend le code un petit peu plus clair. Judicieux.
Merci. jm
Eric Deveaud
wrote:
encore un peu plus rapide en remplacant la fin de test4():
choice = ( blanc, noir) # astuce pour eviter le look ahead ... maintenant inutile carac=chr(128) return [choice[pix < carac] for pix in data1[::3]]
on evite ainsi le ord()....
joli et un code plus facile a lire.
Eric
--
Ça fait des années que septembre dure 12 mois. Cette année, cependant, les cons de l'année prochaine sont en avance. -+- CHC in GCU -- Y'a plus d'saisons ma pôv dame -+-
aaa@aaa.fr wrote:
encore un peu plus rapide en remplacant la fin de test4():
choice = ( blanc, noir)
# astuce pour eviter le look ahead ... maintenant inutile
carac=chr(128)
return [choice[pix < carac] for pix in data1[::3]]
on evite ainsi le ord()....
joli et un code plus facile a lire.
Eric
--
Ça fait des années que septembre dure 12 mois.
Cette année, cependant, les cons de l'année prochaine sont en avance.
-+- CHC in GCU -- Y'a plus d'saisons ma pôv dame -+-
encore un peu plus rapide en remplacant la fin de test4():
choice = ( blanc, noir) # astuce pour eviter le look ahead ... maintenant inutile carac=chr(128) return [choice[pix < carac] for pix in data1[::3]]
on evite ainsi le ord()....
joli et un code plus facile a lire.
Eric
--
Ça fait des années que septembre dure 12 mois. Cette année, cependant, les cons de l'année prochaine sont en avance. -+- CHC in GCU -- Y'a plus d'saisons ma pôv dame -+-
Eric
Eric Deveaud wrote:
je propose pour illustrer les 4 codes suivants et leur bench respectifs def test4(): return [choice[o(pix) < 128] for pix in data1[::3]]
Il faut juste ajouter le join dans test4() : return ''.join([choice[o(pix) < 128] for pix in data1[::3]])
il y a tout de meme une sacré echelle de différence non ??
...et c'est effectivement plus que satisfaisant. J'ai intégré ce code dans l'appli que j'ai utilisé pour faire le test avec wx, et les images sont affichées maintenant dans un temps tout à fait acceptable compte tenu de leur taille (qlques secondes). De plus, les solutions évoquées m'ouvrent des horizons pour d'autres optimisations. Si quelqu'un est intéressé par un code complet et autonome avec wx pour transformer une série d'images, il n'a qu'à demander.
bien sur que l'on est interessé ! Ca serait bien de voir ce fameux code....
Merci pour toutes les réponses. A+ jm PS: autre solution évoquée par un ami: le regexp ; mais est-ce vraiment pythonien ?
Eric2
Eric Deveaud wrote:
je propose pour illustrer les 4 codes suivants et leur bench respectifs
def test4():
return [choice[o(pix) < 128] for pix in data1[::3]]
Il faut juste ajouter le join dans test4() :
return ''.join([choice[o(pix) < 128] for pix in data1[::3]])
il y a tout de meme une sacré echelle de différence non ??
...et c'est effectivement plus que satisfaisant.
J'ai intégré ce code dans l'appli que j'ai utilisé pour faire le test
avec wx, et les images sont affichées maintenant dans un temps tout à
fait acceptable compte tenu de leur taille (qlques secondes).
De plus, les solutions évoquées m'ouvrent des horizons pour d'autres
optimisations.
Si quelqu'un est intéressé par un code complet et autonome avec wx pour
transformer une série d'images, il n'a qu'à demander.
bien sur que l'on est interessé ! Ca serait bien de voir ce fameux code....
Merci pour toutes les réponses.
A+
jm
PS: autre solution évoquée par un ami: le regexp ; mais est-ce vraiment
pythonien ?
je propose pour illustrer les 4 codes suivants et leur bench respectifs def test4(): return [choice[o(pix) < 128] for pix in data1[::3]]
Il faut juste ajouter le join dans test4() : return ''.join([choice[o(pix) < 128] for pix in data1[::3]])
il y a tout de meme une sacré echelle de différence non ??
...et c'est effectivement plus que satisfaisant. J'ai intégré ce code dans l'appli que j'ai utilisé pour faire le test avec wx, et les images sont affichées maintenant dans un temps tout à fait acceptable compte tenu de leur taille (qlques secondes). De plus, les solutions évoquées m'ouvrent des horizons pour d'autres optimisations. Si quelqu'un est intéressé par un code complet et autonome avec wx pour transformer une série d'images, il n'a qu'à demander.
bien sur que l'on est interessé ! Ca serait bien de voir ce fameux code....
Merci pour toutes les réponses. A+ jm PS: autre solution évoquée par un ami: le regexp ; mais est-ce vraiment pythonien ?
Eric2
jean-michel bain-cornu
Bonjour, Eric wrote:
Si quelqu'un est intéressé par un code complet et autonome avec wx pour transformer une série d'images, il n'a qu'à demander.
bien sur que l'on est interessé ! Ca serait bien de voir ce fameux code.... Voilà donc le code ci-après.
J'ai essayé d'épurer au maxi afin de ne conserver que la partie imagerie. C'est pas sorcier, finalement (environ 30 lignes). J'ai connu des gui plus gourmands... Quelqu'un peut-il faire mieux avec un autre GUI ? A+ jm PS: je le mets dans le wiki dès que j'ai une minute.
# -*- coding: iso-8859-1 -*- import wx #---------------------------------------------------------------------- # nb: le fichier jpeg doit être présent class mainWindow(wx.Frame): def __init__(self): wx.Frame.__init__(self,None,wx.ID_ANY,'Affichage images') #--le sizer va servir à positionner les images et dimensionner la fenêtre sizerH= wx.BoxSizer(wx.HORIZONTAL) #--l'image est d'abord affichée telle que... img= wx.Image('amélie.jpg',wx.BITMAP_TYPE_JPEG) bmp= wx.BitmapFromImage(img) staticBmp= wx.StaticBitmap(self,wx.ID_ANY,bmp) sizerH.Add(staticBmp) #--...puis modifiée pour ne conserver que du blanc et du noir data1= img.GetData() blanc= chr(255)*3 noir= chr(0)*3 choice= (blanc, noir) seuil= chr(128) # changer la valeur pour un résultat différent (un seuil élevé pour une image pâle) data2= ''.join([choice[pix < seuil] for pix in data1[::3]]) img.SetData(data2) bmp= wx.BitmapFromImage(img) staticBmp= wx.StaticBitmap(self,wx.ID_ANY,bmp) sizerH.Add(staticBmp) #--régler la taille de la fenêtre self.SetSizer(sizerH) self.SetAutoLayout(1) sizerH.Fit(self) #-- self.Show(True) #---------------------------------------------------------------------- app = wx.PySimpleApp() frame=mainWindow() app.MainLoop() del app #----------------------------------------------------------------------
Bonjour,
Eric wrote:
Si quelqu'un est intéressé par un code complet et autonome avec wx
pour transformer une série d'images, il n'a qu'à demander.
bien sur que l'on est interessé ! Ca serait bien de voir ce fameux code....
Voilà donc le code ci-après.
J'ai essayé d'épurer au maxi afin de ne conserver que la partie imagerie.
C'est pas sorcier, finalement (environ 30 lignes). J'ai connu des gui
plus gourmands... Quelqu'un peut-il faire mieux avec un autre GUI ?
A+
jm
PS: je le mets dans le wiki dès que j'ai une minute.
# -*- coding: iso-8859-1 -*-
import wx
#----------------------------------------------------------------------
# nb: le fichier jpeg doit être présent
class mainWindow(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None,wx.ID_ANY,'Affichage images')
#--le sizer va servir à positionner les images et dimensionner
la fenêtre
sizerH= wx.BoxSizer(wx.HORIZONTAL)
#--l'image est d'abord affichée telle que...
img= wx.Image('amélie.jpg',wx.BITMAP_TYPE_JPEG)
bmp= wx.BitmapFromImage(img)
staticBmp= wx.StaticBitmap(self,wx.ID_ANY,bmp)
sizerH.Add(staticBmp)
#--...puis modifiée pour ne conserver que du blanc et du noir
data1= img.GetData()
blanc= chr(255)*3
noir= chr(0)*3
choice= (blanc, noir)
seuil= chr(128) # changer la valeur pour un résultat différent
(un seuil élevé pour une image pâle)
data2= ''.join([choice[pix < seuil] for pix in data1[::3]])
img.SetData(data2)
bmp= wx.BitmapFromImage(img)
staticBmp= wx.StaticBitmap(self,wx.ID_ANY,bmp)
sizerH.Add(staticBmp)
#--régler la taille de la fenêtre
self.SetSizer(sizerH)
self.SetAutoLayout(1)
sizerH.Fit(self)
#--
self.Show(True)
#----------------------------------------------------------------------
app = wx.PySimpleApp()
frame=mainWindow()
app.MainLoop()
del app
#----------------------------------------------------------------------
Si quelqu'un est intéressé par un code complet et autonome avec wx pour transformer une série d'images, il n'a qu'à demander.
bien sur que l'on est interessé ! Ca serait bien de voir ce fameux code.... Voilà donc le code ci-après.
J'ai essayé d'épurer au maxi afin de ne conserver que la partie imagerie. C'est pas sorcier, finalement (environ 30 lignes). J'ai connu des gui plus gourmands... Quelqu'un peut-il faire mieux avec un autre GUI ? A+ jm PS: je le mets dans le wiki dès que j'ai une minute.
# -*- coding: iso-8859-1 -*- import wx #---------------------------------------------------------------------- # nb: le fichier jpeg doit être présent class mainWindow(wx.Frame): def __init__(self): wx.Frame.__init__(self,None,wx.ID_ANY,'Affichage images') #--le sizer va servir à positionner les images et dimensionner la fenêtre sizerH= wx.BoxSizer(wx.HORIZONTAL) #--l'image est d'abord affichée telle que... img= wx.Image('amélie.jpg',wx.BITMAP_TYPE_JPEG) bmp= wx.BitmapFromImage(img) staticBmp= wx.StaticBitmap(self,wx.ID_ANY,bmp) sizerH.Add(staticBmp) #--...puis modifiée pour ne conserver que du blanc et du noir data1= img.GetData() blanc= chr(255)*3 noir= chr(0)*3 choice= (blanc, noir) seuil= chr(128) # changer la valeur pour un résultat différent (un seuil élevé pour une image pâle) data2= ''.join([choice[pix < seuil] for pix in data1[::3]]) img.SetData(data2) bmp= wx.BitmapFromImage(img) staticBmp= wx.StaticBitmap(self,wx.ID_ANY,bmp) sizerH.Add(staticBmp) #--régler la taille de la fenêtre self.SetSizer(sizerH) self.SetAutoLayout(1) sizerH.Fit(self) #-- self.Show(True) #---------------------------------------------------------------------- app = wx.PySimpleApp() frame=mainWindow() app.MainLoop() del app #----------------------------------------------------------------------