IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Calcul scientifique Python Discussion :

Parcours d'une image .png + création d'autant d'images qu'il y a de couleurs = lenteur désespérante !


Sujet :

Calcul scientifique Python

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut Parcours d'une image .png + création d'autant d'images qu'il y a de couleurs = lenteur désespérante !
    Bonjour,

    Je m'amuse avec Python et la librairie PIL, bon a un très petit niveau

    Le but est de traiter une image de 22528 x 22528 pixels (limite max actuelle):
    1. Créer une image .png vide de la même dimension que l'image traitée
    2. Parcourir l'image traitée pixel par pixel
    3. Pour chaque pixel, test de la valeur des canaux RGB, si égale à une valeur donnée
    4. Modification des valeurs du pixel à la même position dans l'image vide créer
    5. Enregistrement de l'image

    Le processus est répété pour 32 couleurs différentes !

    Bilan des courses plus de 6 heures de moulinage actif du bousin

    Lorsque je compare avec GIMP et la vitesse de sélection d'un ensemble de pixels ayant la même couleur, je me dis que je dois être au niveau zéro de l'algorithmique optimisée !!!!
    Par contre je m'épargne une séance de click sous GIMP. L'idée initiale était de faire un script GIMP, j'ai reculé devant l'obstacle

    Comment améliorer la vitesse d’exécution ?

    Au plaisir de vous lire !

    Ci-joint le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    #Changing Individual Pixels
     
    from PIL import Image
    import time 
    #Desable "DecompressionBombWarning"
    Image.MAX_IMAGE_PIXELS = None
     
    #Compteur de temps
    tmps1=time.time()
    print(tmps1)
     
    #Code département
    Departement="03"
    #Chemin racine des dossiers à traiter
    Chemin = "D:\\#GIS\\Inventaire forestier\\"
    #Dossier à traiter
    Dossier = Chemin + Departement + "\\"
    #Image téléchargée
    NomImTel = "Base_" + Departement + ".png"
     
     
     
    #Ouverture de l'image téléchargée
    ImTel = Image.open(Dossier + NomImTel)
    ImTel = ImTel.convert('RGB')
     
    width, height = ImTel.size
     
    print(str(width)+","+str(height))
     
    Dossier = "D:\\#GIS\\Inventaire forestier\\03\\"
    FormatImage = ".png"
     
    #Liste des codes couleurs associés au type de forêt
    CodesCouleurListe=[\
    	["JpCrI",229,196,93],\
    	["Fp",1,120,56],\
    	["Cdp",0,77,46],\
    	["Csp",102,128,64],\
    	["Hp",0,185,168],\
    	["Cp",64,255,38],\
    	["Rp",145,86,51],\
    	["Afp",175,202,89],\
    	["Mf",0,147,27],\
    	["P",255,255,50],\
    	["Cpi",128,128,255],\
    	["Pmp",191,38,255],\
    	["Psp",153,38,255],\
    	["PlPnp",57,11,215],\
    	["Pap",255,26,205],\
    	["PcPcp",135,97,250],\
    	["App",216,152,255],\
    	["Mpp",255,153,255],\
    	["Sep",26,230,230],\
    	["Mp",97,128,255],\
    	["Dp",51,153,255],\
    	["Acp",169,255,255],\
    	["Mac",1,146,159],\
    	["Mc",0,0,255],\
    	["Mfpc",255,152,51],\
    	["Mcpf",255,64,51],\
    	["FocrI",178,158,147],\
    	["Fofp",204,255,191],\
    	["Focp",153,179,204],\
    	["Fomfc",255,209,56],\
    	["Ll",255,230,191],\
    	["Fh",255,255,185]]
     
     
     
    #Boucle sur la liste
    for Foret, Red, Green, Blue in CodesCouleurListe:
    	#Boolean de test présence pixel
    	FindPixel=False
    	ImType=Image.new('RGBA',(width,height)) #Création d'une instance d'image à le même taille que l'image de base
    	for x in range(width): #Itération du X pixels
    		for y in range(height): #Itération du Y pixels
    			r,g,b=ImTel.getpixel((x, y))
    			if r==Red and g==Green and b==Blue:
    				FindPixel=True
    				ImType.putpixel((x, y), (145, 86, 51))
            #Si la condition est vrai enregistrement image
    	if FindPixel==True:
    		Adresse = Dossier + Departement + "_" + Foret + FormatImage
    		ImType.save(Adresse)
     
     
     
    tmps2=time.time()
    print(tmps2)
    print ("Temps d'execution = %f" %tmps2)

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Citation Envoyé par Richelsdorfite Voir le message
    Comment améliorer la vitesse d’exécution ?
    Pour l'algorithme, le bon forum est celui de la rubrique algorithmique.
    Côté vitesse d’exécution, vous avez 2 boucles:
    la boucle interne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	for x in range(width): #Itération du X pixels
    		for y in range(height): #Itération du Y pixels
    			r,g,b=ImTel.getpixel((x, y))
    			if r==Red and g==Green and b==Blue:
    				FindPixel=True
    				ImType.putpixel((x, y), (145, 86, 51))
    la boucle externe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    for Foret, Red, Green, Blue in CodesCouleurListe:
    	#Boolean de test présence pixel
    	FindPixel=False
    	ImType=Image.new('RGBA',(width,height)) #Création d'une instance d'image à le même taille que l'image de base
            ....
    	if FindPixel==True:
    		Adresse = Dossier + Departement + "_" + Foret + FormatImage
    		ImType.save(Adresse)
    Pour la boucle interne, il faudrait essayer ce que donne numpy qui sait faire des choses comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> x = numpy.array([1,0,2,0,3,0,4,5,6,7,8])
    >>> y = numpy.where(x == 0)
    >>> x[y] = 99
    >>> x
    array([ 1, 99,  2, 99,  3, 99,  4,  5,  6,  7,  8])
    >>>
    sur des tableaux à plusieurs dimensions modulo la conversion des Image en tableau (il y a des méthodes).

    Cela fait, la boucle externe se parallélise avec multiprocessing (et la supposition que vous avez plusieurs CPU à faire tourner).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut
    Merci pour ces conseils !

    Effectivement l'option numpy m'a traversé l'esprit, je suis en train de me pencher dessus. Aie !

    Néanmoins la boucle externe ne me semble pas être le pb, le pb réside dans le parcours de d'un demi million de pixels.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for x in range(width): #Itération du X pixels
    		for y in range(height): #Itération du Y pixels
    Un demi million d'itérations vs 32 itérations le problème est cerné ;-)

    Reste à maîtriser numpy ou une partie de numpy

    Si avec numpy le temps de traitement pour une couleur donnée descend de façon drastique c'est gagné.
    Actuellement une boucle interne prend, en moyenne, 10 à 15 minutes.
    L'idée serait de descendre ce temps entre 1 et 5 minutes histoire de ne pas y passer la nuit et subir ces aléas (coupure de jus etc...)

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut
    Afin d'illustrer mon propos et à but de test, voici un exemple d'image à traiter : https://drive.google.com/file/d/0B9X...ew?usp=sharing

    Attention fichier .png de 7779 Ko !

  5. #5
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    il semblerait que la modification suivante soit 5x plus rapide (sur ma machine tout du moins) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # ici j'ai transformé en dictionnaire, ça n'est pas vraiment utile, en revanche regrouper les valeurs en sets est plus pertinent
    CodesCouleurListe = {
       (229,196,93):'JpCrI',   (1,120,56):'Fp',        (0,77,46):'Cdp',        (102,128,64):'Csp',
       ...
     
    ImTel = Image.open(Dossier + NomImTel).convert('RGB')
    pix = ImTel.load()
    ...
    # ici on récupère la palette exhaustive de l'image, puis on fait l'intersection avec la liste des codes couleurs qu'on veut traiter
    # à voir si c'est pertinent ou non, sachant que ça impacte la mémoire avec une liste supplémentaire...
    # (sur le fichier que tu as donné ce matin (...) on évite le traitement de 2 ou 3 codes couleur sur l'ensemble)
    paletteImage = [i[1] for i in ImTel.getcolors(maxcolors=width*height)]
    listeCouleursATraiter = set(paletteImage) & set(CodesCouleurListe.keys())
    for pixel in listeCouleursATraiter:
       if pix[x,y] == pixel:  # semble remplacer avantageusement getpixel()
          ...
    Attention fichier .png de 7779 Ko !
    et encore, l'image est compressée, une fois étalée en bitmap c'est au moins ~1G en mémoire...
    j'ai cru lire par ailleurs que numpy était une bonne solution comme l'indiquait wiztricks, au prix de x3 en mémoire on a du x5 en vitesse, à considérer...

    Edit: une dernière idée me vient en tête, les codes couleurs que tu cherches à traiter, s'il y en a moins de 256, est-ce qu'il ne serait pas possible de convertir l'image en 8bits avec une palette ? le filtrage deviendrait alors trivial à coups de ImTel.point() et ultra rapide...

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par BufferBob Voir le message
    il semblerait que la modification suivante soit 5x plus rapide (sur ma machine tout du moins)
    Si on compare çà:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    def set_array_rgb(array, rgb, values):
        r, g, b = rgb
        rows, cols = np.where((array[...,0]==r) &
                              (array[...,1]==g) &
                              (array[...,2]==b))
        if len(rows):
            array[rows,cols] = values
     
    def set_image_rgb(image, rgb, values):
        width, height = image.size
        Red, Green, Blue = rgb
        for x in range(width): #Itération du X pixels
                for y in range(height): #Itération du Y pixels
                    r,g,b = image.getpixel((x, y))
                    if r==Red and g==Green and b==Blue:
                        FindPixel=True
                        image.putpixel((x, y), values)
    numpy va plus de 50X plus vite sur des images inférieures à 5000x5000 dans lesquelles je remplace tous les points - j'ai pas encore testé plus grand: çà bouffe de la mémoire, çà prend du temps et j'ai envie de tester autre chose.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut
    Vous allez trop vite pour moi

    J'explore le code de BufferBob et hop une autre solution arrive !

    Quoiqu'il en soit, merci à vous !

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut
    Citation Envoyé par BufferBob Voir le message
    salut,

    il semblerait que la modification suivante soit 5x plus rapide (sur ma machine tout du moins) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # ici j'ai transformé en dictionnaire, ça n'est pas vraiment utile, en revanche regrouper les valeurs en sets est plus pertinent
    CodesCouleurListe = {
       (229,196,93):'JpCrI',   (1,120,56):'Fp',        (0,77,46):'Cdp',        (102,128,64):'Csp',
       ...
     
    ImTel = Image.open(Dossier + NomImTel).convert('RGB')
    pix = ImTel.load()
    ...
    # ici on récupère la palette exhaustive de l'image, puis on fait l'intersection avec la liste des codes couleurs qu'on veut traiter
    # à voir si c'est pertinent ou non, sachant que ça impacte la mémoire avec une liste supplémentaire...
    # (sur le fichier que tu as donné ce matin (...) on évite le traitement de 2 ou 3 codes couleur sur l'ensemble)
    paletteImage = [i[1] for i in ImTel.getcolors(maxcolors=width*height)]
    listeCouleursATraiter = set(paletteImage) & set(CodesCouleurListe.keys())
    for pixel in listeCouleursATraiter:
       if pix[x,y] == pixel:  # semble remplacer avantageusement getpixel()
          ...

    et encore, l'image est compressée, une fois étalée en bitmap c'est au moins ~1G en mémoire...
    j'ai cru lire par ailleurs que numpy était une bonne solution comme l'indiquait wiztricks, au prix de x3 en mémoire on a du x5 en vitesse, à considérer...

    Edit: une dernière idée me vient en tête, les codes couleurs que tu cherches à traiter, s'il y en a moins de 256, est-ce qu'il ne serait pas possible de convertir l'image en 8bits avec une palette ? le filtrage deviendrait alors trivial à coups de ImTel.point() et ultra rapide...
    Code modifié, je viens de lancer le traitement verdict dans 1 heure ou 6

    Edit : temps de traitement d'environ 5 minutes par couleur soit en théorie 2H40 de traitement > division par deux du temps de traitement, on se rapproche du temps mis à faire la même chose manuellement avec GIMP

    Je vais explorer, demain, numpy et la conversion image en 8 bits car j'ai au max 32 couleurs à extraire.

    Merci à vous et bonne nuit !

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut
    Temps de traitement 1h17 min pour 28 couleurs extraites > 2'48" par couleur pour 11'15 avec ma méthode de brute !
    Je suis donc dans l'ordre de temps d'un traitement manuel sous GIMP sans le coté stakhanoviste de la chose !

    Gain de facteur 4 !

    Youpi !


    Pourquoi la méthode et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    putpixel((x, y), (145, 86, 51))
    est-elle si lente ?
    Une recherche sur Stackoverflow donne : http://stackoverflow.com/questions/2...ate-pixel-data
    et renvoie à la méthode pour une image en niveau de gris.

    Merci à BufferBob !


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #Changing Individual Pixels
    import PIL
    from PIL import Image
    import numpy
    import time 
    #Desable "DecompressionBombWarning"
    Image.MAX_IMAGE_PIXELS = None
     
    #Compteur de temps
    tmps1=time.time()
    print(tmps1)
     
    #Code département
    Departement="03"
    #Chemin racine des dossiers à traiter
    Chemin = "D:\\#GIS\\Inventaire forestier\\"
    #Dossier à traiter
    Dossier = Chemin + Departement + "\\"
    #Image téléchargée
    NomImTel = "Base_" + Departement + ".png"
     
     
    #Ouverture de l'image téléchargée
    ImTel = Image.open(Dossier + NomImTel).convert('RGB')
    pix = ImTel.load()
    width, height = ImTel.size
    print(str(width)+","+str(height))
     
    Dossier = "D:\\#GIS\\Inventaire forestier\\03\\"
    FormatImage = ".png"
     
    #Liste des codes couleurs associés au type de forêt
    CodesCouleurListe={(229,196,93):'JpCrI',(1,120,56):'Fp',(0,77,46):'Cdp',(102,128,64):'Csp',(0,185,168):'Hp',(64,255,38):'Cp',(145,86,51):'Rp',(175,202,89):'Afp',(0,147,27):'Mf',(255,255,50):'P',(128,128,255):'Cpi',(191,38,255):'Pmp',(153,38,255):'Psp',(57,11,215):'PlPnp',(255,26,205):'Pap',(135,97,250):'PcPcp',(216,152,255):'App',(255,153,255):'Mpp',(26,230,230):'Sep',(97,128,255):'Mp',(51,153,255):'Dp',(169,255,255):'Acp',(1,146,159):'Mac',(0,0,255):'Mc',(255,152,51):'Mfpc',(255,64,51):'Mcpf',(178,158,147):'FocrI',(204,255,191):'Fofp',(153,179,204):'Focp',(255,209,56):'Fomfc',(255,230,191):'Ll',(255,255,185):'Fh',}
     
    paletteImage = [i[1] for i in ImTel.getcolors(maxcolors=width*height)]
    listeCouleursATraiter = set(paletteImage) & set(CodesCouleurListe.keys())
     
    for pixel in listeCouleursATraiter:
    	ImType=Image.new('RGBA',(width,height))
    	for x in range(width):
    		for y in range(height):
    			if pix[x,y] == pixel:
    				ImType.putpixel((x, y), (145, 86, 51))
    	Couche =CodesCouleurListe.get(pixel)
    	Adresse = Dossier + Departement + "_" + Couche + FormatImage
    	ImType.save(Adresse)
     
     
    tmps2=time.time()
    print(tmps2)
    print ("Temps d'execution = %f" %tmps2)

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2011
    Messages
    252
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2011
    Messages : 252
    Points : 649
    Points
    649
    Par défaut Fonctions get/putpixel rapides & 32 vs 8 bits
    Elles gèrent les composants RVB, sans doute le clipping et d'autres trucs… Le mieux serait de lire/écrire tes pixels en brut à savoir leur couleur en hexadécimal. Donc tu peux encore optimiser listeCouleursATraiter et évidemment remplacer putpixel par une autre fonction. Il n'y a pas une espèce de fastputpixel ? En plus la couleur que tu utilises est toujours la même donc autant oublier le code RVB.

    Sinon sur une architecture 32 bits ça sera pas forcément plus rapide de traiter une image 8 bits. Ça devrait même être le contraire mais mes connaissances sont un peu rouillées ! L'éternel dilemne entre mémoire, processeur…

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2011
    Messages
    252
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2011
    Messages : 252
    Points : 649
    Points
    649
    Par défaut Exemple d'image
    Tu peux fournir une image plus petite ? À ce stade tu devrais même te contenter de ça au lieu d'utiliser la géante. D'ailleurs de toi-même tu extrapoles des statistiques, indépendantes de la taille, et le traitement reste le même.

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2011
    Messages
    252
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2011
    Messages : 252
    Points : 649
    Points
    649
    Par défaut Processus, usage et algo en une passe
    Je me permets de reprendre tout depuis le début pour déterminer si tu pars dans la bonne direction ou non.

    Donc d'après ton processus l'objectif c'est de créer autant de masques qu'il y a de couleurs. Pour quel usage ? Est-ce que tes images sont exploitables ? C'est important car tu te retrouves avec des images immenses et si c'est par exemple pour un simple affichage dynamique au survol de la souris… De plus dans l'idéal ton algorithme devrait être indépendant du nombre de couleurs. Aujourd'hui 32 mais peut-être demain 64, 128…

    Je vois 2 optimisations majeures en plus des autres évoquées :
    • Virer la boucle externe car même si l'interne est très gourmande au final on se retrouve 32 fois à la faire ! Une solution serait l'utilisation d'une table de hachage afin d'adresser directement les couleurs… L'approche de BufferBob semble améliorer les choses en éliminant des couleurs notamment si j'ai bien compris car ça doit pouvoir se faire en une passe.
    • … mais ça dépend d'une autre approche. Pourquoi ne pas découper tes images ? Le choix d'une taille dépend de plusieurs paramètres dont l'usage et les ressources disponibles (Mémoire & Cie). Rien qu'en 1024 pixels ça te permettrait de tout avoir en mémoire.

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut
    Le but de la manip est, in fine de vectoriser les rasters produits afin de pouvoir effectuer des traitements géospatiaux sur les .shp produits.

    Je procède donc, pour le moment, à l'extraction des couleurs. Celle-ci sont limitées à 32 couleurs mais effectivement il est possible d'avoir, sur d'autres jeux de données, une palette plus large.
    Je me penche sur la GDAL/ORG afin de polygoniser mes rasters géoréférencés.

    Le jeu de donnée actuel est diffusé par département, mes limitations matérielles ou software ne me permette, pour le moment, que d'assembler une mosaïque d'image 2048*2048 pixels dans un image en 11*2048 x 11*2048. Ce qui me donne une résolution de 6m/pixel. C'est amplement suffisant pour l'utilisation que je vais en faire. L'idée m'a bien traversé l'esprit de descendre à 1m/pixel au prix d'un facteur 36 !!!! Inimaginable dans le cadre des traitements postérieurs même à mes 16 Go de mémoire vive ! J'ai bien imaginé découper le département en plusieurs images par exemple en 36 images de 22528 x 22528 à 1m/pixel mais cela me posera problème lors de la polygonisation, je n'ai pas du tout envie de devoir faire l'union de certains polygones afin de reconstituer la cohérence au sein d'un département.

    J'essaye l'approche "numpy" qui serait cohérente avec l'utilisation, par la suite, de GDAL. C'est, en l'état actuel de mes connaissances, pas si simple que cela. Mais j'ai bon espoir d'y arriver entre le placo, le carrelage, et mes cours de technologie avion....

    Actuellement, je traite ces images manuellement sous QGIS. Cela explique le code couleur unique , QGIS étant incapable de polygoniser sur une couleur , il faut que j'essaye .

    Pour le moment, je bloque sur la transformation de l'image 32 bits en 8 bits en utilisant un palette. L'idée de BufferBob est vraiment bien et cela allégerait le traitement avec numpy et le hachage.

    Le lien vers une image en 2048x2048 : https://drive.google.com/file/d/0B9X...ew?usp=sharing

  14. #14
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    Citation Envoyé par Richelsdorfite Voir le message
    Pour le moment, je bloque sur la transformation de l'image 32 bits en 8 bits en utilisant un palette.
    un truc dans ce style prend en tout et pour tout une dizaine de secondes avec le base2048.png que tu as donné :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    ImTel = Image.open('base2048.png')  # note pas de convert() ici
    pix = ImTel.load()
    width, height = ImTel.size
     
    # pas particulierement utile mais comme j'etais parti sur un dico...
    CodesCouleurListe = {
       (229,196,93):'JpCrI',   (1,120,56):'Fp',        (0,77,46):'Cdp',        (102,128,64):'Csp',
       (0,185,168):'Hp',       (64,255,38):'Cp',       (145,86,51):'Rp',       (175,202,89):'Afp',
       (0,147,27):'Mf',        (255,255,50):'P',       (128,128,255):'Cpi',    (191,38,255):'Pmp',
       (153,38,255):'Psp',     (57,11,215):'PlPnp',    (255,26,205):'Pap',     (135,97,250):'PcPcp',
       (216,152,255):'App',    (255,153,255):'Mpp',    (26,230,230):'Sep',     (97,128,255):'Mp',
       (51,153,255):'Dp',      (169,255,255):'Acp',    (1,146,159):'Mac',      (0,0,255):'Mc',
       (255,152,51):'Mfpc',    (255,64,51):'Mcpf',     (178,158,147):'FocrI',  (204,255,191):'Fofp',
       (153,179,204):'Focp',   (255,209,56):'Fomfc',   (255,230,191):'Ll',     (255,255,185):'Fh'
    }
     
    # on convertit "manuellement", c'est l'operation qui prend le plus de temps
    Im8b = Image.new('P', (width,height), 0)
    palette = [(0,0,0)] + CodesCouleurListe.keys()  # palette[0] = background = noir
    Im8b.putpalette([val for RGBtriple in palette for val in RGBtriple])
    for y in range(height):
       for x in range(width):
          coul = pix[x,y][:3]  # on exclue le canal alpha manuellement, parce qu'on a pas convert() plus haut ;)
          if coul in palette[1:]:
             Im8b.putpixel((x, y), palette.index(coul))
     
    # on traite nos codes couleurs, l'ensemble ne prend qu'une poignee de secondes, sauvegarde inclue
    pix2 = Im8b.load()
    for i in CodesCouleurListe.keys():
       coul = palette.index(i)
       ImType = Im8b.point(lambda x:x if x == coul else 0)
       ImType = ImType.convert('RGBA')  # mais est-ce necessaire ??
       ImType.save('base2048_{}.png'.format(CodesCouleurListe[i]))
    avec le fichier original (base.png, 22528x16384) la conversion prend ~8min, au delà j'ai un memory error du fait de py2 / pillow 3.4.2 à priori

  15. #15
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2011
    Messages
    252
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2011
    Messages : 252
    Points : 649
    Points
    649
    Par défaut Contraintes et solutions pertinentes
    Merci pour les explications c'est important de considérer les traitements pour pas se planter en amont. Si la résolution choisie est suffisante pour générer les polygones tant mieux. Par contre faut pas brider ton système à cause d'un problème. Au contraire il faut voir les contraintes, la mémoire limitée par exemple, pour trouver une solution pertinente. Même en astronomie elles existent ! En plus 16 Go c'est démesuré pour de telles opérations. D'où l'intérêt vraiment d'un découpage mais je vois que tu as déjà pensé à l'assemblage/la mosaïque. Mais si c'est gérable pour des images ça l'est aussi pour des polygones. D'ailleurs est-ce que fusionner les polygones de plusieurs zones est important ? Ça empêche pas l'affichage même si en matière de cartographie il doit exister des solutions bien plus évoluées. Je pense notamment à la possibilité de zoomer sans provoquer l'apparition de coutures. Enfin ça mérite sans doute une autre discussion mais le sujet est intéressant !

    Bon courage t'es en bonne voie et vive les images palettisées.

  16. #16
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut
    @Bufferbob

    J'ai une erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Traceback (most recent call last):
      File "D:\#GIS\Inventaire forestier\Conversion 8bits.py", line 30, in <module>
        palette = [(0,0,0)] + CodesCouleurListe.keys()  # palette[0] = background = noir
    TypeError: can only concatenate list (not "dict_keys") to list
    que j'ai résolu en créant une liste
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    palette = [(0,0,0)] + list(CodesCouleurListe.keys())
    Le processus mouline mais me sort des images en 32 bits. Je pense que c'est du au
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ImType = ImType.convert('RGBA')  # mais est-ce necessaire ??
    J'ai donc supprimé cette ligne et je relance le moulin.

  17. #17
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut
    Les images extraites sont bien en 8 bits.

    Temps de traitement :

    Application de la palette 8 bits > 12'36"
    Temps moyen d'extraction d'une couche > 3.71"
    Temps total d'extraction des 32 couches > 1'59"

    TEMPS total d'éxécution : 14'36"

    C'est une nette accélération !

  18. #18
    Membre chevronné
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2013
    Messages
    1 608
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2013
    Messages : 1 608
    Points : 2 072
    Points
    2 072
    Par défaut
    J'ai une question bête : D ne serait pas une clé USB par hasard ?
    Parce que si oui, c'est à mon avis cela le frein à main.

    (6" (6 secondes) chez moi avec getTile et le programme du post #9)
    Pas d'aide par mp.

  19. #19
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 27
    Points : 10
    Points
    10
    Par défaut
    Citation Envoyé par marco056 Voir le message
    J'ai une question bête : D ne serait pas une clé USB par hasard ?
    Parce que si oui, c'est à mon avis cela le frein à main.

    (6" (6 secondes) chez moi avec getTile et le programme du post #9)
    Non ce n'est pas une clef ;-)

    Par contre avec quelle image avez-vous fait le test ? Une en 2048 ou en 22528 pixels ?

  20. #20
    Membre chevronné
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2013
    Messages
    1 608
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2013
    Messages : 1 608
    Points : 2 072
    Points
    2 072
    Par défaut
    La petite en 2048.
    Pas d'aide par mp.

Discussions similaires

  1. java/opencv : Création d'une image png à partir de sa chaîne ?
    Par blackbird1 dans le forum API standards et tierces
    Réponses: 9
    Dernier message: 27/02/2014, 20h44
  2. Création d'une image PNG en C++
    Par magicpm7 dans le forum C++
    Réponses: 5
    Dernier message: 20/04/2007, 08h58
  3. [ImageMagick] Affichage d'une image png
    Par JavaAcro dans le forum Bibliothèques et frameworks
    Réponses: 15
    Dernier message: 06/02/2006, 09h13
  4. [Image] Décomposer une image png.
    Par Quintoff dans le forum 2D
    Réponses: 3
    Dernier message: 06/01/2006, 20h22
  5. [Cross-Browser] Couleur d'une image PNG
    Par [BkM-) dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 17/11/2005, 21h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo