Point Cloud (Liste logique)

Ici on parle des scripts

Modérateurs : frez, Yadoob, stilobique, Matpi, ModSquad

Point Cloud (Liste logique)

Message par GameL » 30 Nov 2018, 11:33

Salut à toutes et tous,

J'aurai besoin d'un petit coup de main concernant une optimisation de code.
Actuellement, j'ai un petit script fonctionnel qui me permet de lire les informations d'un fichier texte se présentant de cette manière:

0.00000000 0.58435619 0.92419678 0.454902 0.403922 0.333333 -0.999999 0.000978 0.000978
0.00000000 0.86374521 0.72747529 0.458824 0.411765 0.341176 -0.999999 0.000978 0.000978
0.00000000 0.79955196 0.66729391 0.415686 0.32549 0.25098 -0.999999 0.000978 0.000978
...


C'est un très long fichier listant les points d'un nuage de point (Photogrammétrie). Les chiffres d'une ligne sont dans cette ordre : X,Y,Z,R,G,B,Nx,Ny,Nz

Mon scritpt ci-dessous, me permet de générer une cartographie colorimétrique des coordonnées XYZ de chaque point.

Voila le problème: Pour le moment tout fonctionne sur des listes de 10 000 coordonnées. Mais dès que je passe à 100K ça commence à devenir beaucoup trop long, sachant que mes listes vont dans l'avenir faire plusieurs millions. Serait-il possible de forcer mon script à lire plus intelligemment mes listes et éviter qu'à chaque boucle il recommence la lecture de liste à zéro?

Code : Tout sélectionner
import bpy
import random
import sys
#WARNING!!! Normaliser le modèle 3D en positif X Y Z
# "Xforward" & "Yup" à l'export obj
#rajouter "map_Ka bake.png" dans le mlt du obj avant import CC

# Remove old images
for img in bpy.data.images:
    bpy.data.images.remove(img)

#import PointCloud.txt

PointCloudText='/Users/goideleg/Desktop/WOOD/WOOD_10000point_floatRGB.txt'

#PointCloudtxt to coordinateList
with open(PointCloudText) as f:
    coordinateList = []
    for line in f:
        line = line.split() # to deal with blank
        if line:            # lines (ie skip them)
            line = [float(i) for i in line]
            coordinateList.append(line)

# Grid Size
width= 100
height = 100

# Error message ratio aspect
if height < len(coordinateList) // width:
    print("ERROR")

#Create Image
image_object = bpy.data.images.new(name='test', width=width, height=height,float_buffer=True)
image_object.generated_color = (0,0,0,0)
num_pixels = len(coordinateList)


def grid(x,y):
    return x + width * y

# Set Point Color
def drawPointColor (x,y,R,G,B,A):
   
    pixelNumber = grid(x,y)*4
   
    image_object.pixels[pixelNumber] = R
    image_object.pixels[pixelNumber+1] = G
    image_object.pixels[pixelNumber+2] = B
    image_object.pixels[pixelNumber+3] = A

#Draw Point Color
max = max(len(coordinateList),width)
for i in range(0,max,1):
    j = i % width
    k = i // width
    if i < len(coordinateList):
        R = coordinateList[i][0] # coordinate X = 0
        G = coordinateList[i][1] # coordinate Y = 1
        B = coordinateList[i][2] # coordinate Z = 2
        drawPointColor(j,k,R,G,B,1)
       
#Show result in UV/image Editor
for area in bpy.context.screen.areas :
    if area.type == 'IMAGE_EDITOR' :
            area.spaces.active.image = image_object


Avatar de l’utilisateur
GameL
 
Message(s) : 80
Inscription : 06 Sep 2014, 05:12

Re: Point Cloud (Liste logique)

Message par JanO » 30 Nov 2018, 14:43

Élo,

Je n'y connais rien en python... mais j'ai quand même une question (voire 2). ;)
- À quoi sert la définition d'une grille ? (# Grid Size)
- Et si tu augmentes cette grille (100x100=10 000), que se passe t-il ?
Avatar de l’utilisateur
JanO
 
Message(s) : 136
Inscription : 30 Oct 2015, 22:00

Re: Point Cloud (Liste logique)

Message par GameL » 30 Nov 2018, 15:35

pour ceci

Image
Avatar de l’utilisateur
GameL
 
Message(s) : 80
Inscription : 06 Sep 2014, 05:12

Re: Point Cloud (Liste logique)

Message par JanO » 01 Déc 2018, 12:24

Arf... tu n'as pas répondu à mes questions.

Là, c'est comme si j'avais demandé pourquoi les croissants du boulanger étaient fabriqués à partir d'un morceau de pâte en triangle et que toi, tu me montrais une photo d'un croissant fini en me disant que c'est pour avoir ça dans la vitrine.

Ce n'est pas grave, parfois mes interventions ne sont pas comprises. ;)

Cordialement
Avatar de l’utilisateur
JanO
 
Message(s) : 136
Inscription : 30 Oct 2015, 22:00

Re: Point Cloud (Liste logique)

Message par lapineige » 02 Déc 2018, 10:13

Par curiosité, tu aurais moyen de tester le temps d'exécution de ton script avec et sans
Code : Tout sélectionner
drawPointColor(j,k,R,G,B,1)
dans ta deuxième boucle for ?

Vu que c'est assez long, une simple différence de
Code : Tout sélectionner
time()
avant et après serait déjà une bonne idée.

Je ne suis pas certain que l'opération la plus longue soit simplement de parcourir une fois la liste et de faire quelques calculs simples.
Mon terrier/blog: https://lapineige.fr/wp (l'ancien: le-terrier-de-lapineige.over-blog.com) | Mon GitHub: https://github.com/lapineige/Blender_add-ons | Lapineige's Tools: http://cgcookiemarkets.com/blender/all- ... ompilation
Avatar de l’utilisateur
lapineige
 
Message(s) : 3710
Inscription : 25 Juin 2014, 07:06

Re: Point Cloud (Liste logique)

Message par GameL » 03 Déc 2018, 12:01

JanO a écrit :Élo,

Je n'y connais rien en python... mais j'ai quand même une question (voire 2). ;)
- À quoi sert la définition d'une grille ? (# Grid Size)
- Et si tu augmentes cette grille (100x100=10 000), que se passe t-il ?


My Bad. La def de grille me permet d'indiquer la dimension de mon canvas de dessin (petite matrice 2D)
Si tu augmentes les valeurs, la grille sera plus grande et le script dessinera un pixel avec un alpha à 0 quand il aura fini de lire ma liste

lapineige a écrit :Par curiosité, tu aurais moyen de tester le temps d'exécution de ton script avec et sans
Code : Tout sélectionner
drawPointColor(j,k,R,G,B,1)
dans ta deuxième boucle for ?

Vu que c'est assez long, une simple différence de
Code : Tout sélectionner
time()
avant et après serait déjà une bonne idée.

Je ne suis pas certain que l'opération la plus longue soit simplement de parcourir une fois la liste et de faire quelques calculs simples.


Alors, voila le résultat pour une liste de 10 000 points.
Avec drawPointColor(j,k,R,G,B,1)
0.8622658252716064 seconds
Sans drawPointColor(j,k,R,G,B,1)
0.01330876350402832 seconds
C'est effectivement plus rapide sans le dessin, mais ça me semble logique non?

Mais j'ai l'impression que le script prend beaucoup de temps à aller récupérer les informations de ma liste pour générer les pixels et affecter ses valeurs... Un peu comme si à chaque boucle il recommençait la lecture de ma liste à zéro.
Avatar de l’utilisateur
GameL
 
Message(s) : 80
Inscription : 06 Sep 2014, 05:12

Re: Point Cloud (Liste logique)

Message par lapineige » 03 Déc 2018, 21:17

GameL a écrit :
Alors, voila le résultat pour une liste de 10 000 points.
Avec drawPointColor(j,k,R,G,B,1)
0.8622658252716064 seconds
Sans drawPointColor(j,k,R,G,B,1)
0.01330876350402832 seconds
C'est effectivement plus rapide sans le dessin, mais ça me semble logique non?


Oui. La différence est relativement importante, mais tout ça va très vite, étonnant qu'avec plus de points ça monte autant...
Tu peux tester avec plus de points, sait-on jamais ?
Y'a pas vraiment de raison vu la complexité de l'algo mais bon.

GameL a écrit :Mais j'ai l'impression que le script prend beaucoup de temps à aller récupérer les informations de ma liste pour générer les pixels et affecter ses valeurs... Un peu comme si à chaque boucle il recommençait la lecture de ma liste à zéro.


Je ne vois pas où il pourrait recommencer, si tu lances le script une seule fois.
Mon terrier/blog: https://lapineige.fr/wp (l'ancien: le-terrier-de-lapineige.over-blog.com) | Mon GitHub: https://github.com/lapineige/Blender_add-ons | Lapineige's Tools: http://cgcookiemarkets.com/blender/all- ... ompilation
Avatar de l’utilisateur
lapineige
 
Message(s) : 3710
Inscription : 25 Juin 2014, 07:06

Re: Point Cloud (Liste logique)

Message par GameL » 04 Déc 2018, 10:18

Merci Lapineige pour ta réponse.

Je viens donc de faire un test avec une liste d'1 million de points et voici les résultats:

Sans drawPointColor(j,k,R,G,B,1)
3.5 seconds environ (cf image)

Image

Avec drawPointColor(j,k,R,G,B,1)
J'ai toujours pas le résultat. :D
Cela doit faire 15 minutes que le script tourne et il en est à 40 000 points sur 1 Million. De mémoire j'avais déjà testé, mais le script avait crash au bout d'un moment.
Je pense vraiment qu'il y a moyen d'optimiser tout ça ^^. Mais je sèche. Comme tu le dis l'algo est tout simple. Et il me semble, mais je peux me tromper, que c'est vraiment une question de logique de lecture et d'acquisition des données de ma liste.
Avatar de l’utilisateur
GameL
 
Message(s) : 80
Inscription : 06 Sep 2014, 05:12

Re: Point Cloud (Liste logique)

Message par lapineige » 04 Déc 2018, 10:44

Ben là manifestement c'est l'opération de dessin du pixel qui prend du temps…
Ah moins de trouver une autre méthode pour le faire (qui serait plus rapide), je ne vois pas bien comment tu pourrais l'accélérer.
Tout ce que tu toucheras autant n'agira qu'à la marge.

Et si tu réalises la même opération avec les outils de python, sur une image externe, puis que tu l'importes dans Blender ?
Cette opération me semble anormalement longue.
1 million de pixels, ça ne fait pas une grosse image… (1000*1000)
Mon terrier/blog: https://lapineige.fr/wp (l'ancien: le-terrier-de-lapineige.over-blog.com) | Mon GitHub: https://github.com/lapineige/Blender_add-ons | Lapineige's Tools: http://cgcookiemarkets.com/blender/all- ... ompilation
Avatar de l’utilisateur
lapineige
 
Message(s) : 3710
Inscription : 25 Juin 2014, 07:06

Re: Point Cloud (Liste logique)

Message par GameL » 04 Déc 2018, 16:14

lapineige a écrit :Et si tu réalises la même opération avec les outils de python, sur une image externe, puis que tu l'importes dans Blender ?
Cette opération me semble anormalement longue.


J'allais effectivement partir sur une solution externe à blender, jusqu'à qu'un ami dev vienne à mon aide et trouve une solution très rapidement.
Du coup maintenant rien à voir ^^ la création d'une image avec 1M de points dans ma liste ne prends plus que 6s :D
Visiblement le .pixel de blender est très lent. Il est recommandé de passer par une liste native pour l'édition de pixel sur blender.

Voila le lien qu'il m'a donné:
https://blender.stackexchange.com/questions/3673/why-is-accessing-image-data-so-slow

Voila le code qu'il a amélioré:
Code : Tout sélectionner
import bpy
import random
import sys
import time
#WARNING!!! Normaliser le modèle 3D en positif X Y Z
# "Xforward" & "Yup" à l'export obj
#rajouter "map_Ka bake.png" dans le mlt du obj avant import CC

#timer
then = time.time() #Time before the operations start

# Remove old images
for img in bpy.data.images:
    bpy.data.images.remove(img)

#import PointCloud.txt
PointCloudText='/Users/goideleg/Desktop/WOOD/WOOD_1M_xyz32_rgb8.txt'

#PointCloudtxt to coordinateList
with open(PointCloudText) as f:
    coordinateList = []
    for line in f:
        line = line.split() # to deal with blank
        if line:            # lines (ie skip them)
            line = [float(i) for i in line]
            coordinateList.append(line)

# Grid Size
width= 1000
height = 1000

# Error message ratio aspect
if height < len(coordinateList) // width:
    print("ERROR")

#Create Image
image_object = bpy.data.images.new(name='test', width=width, height=height,float_buffer=True)
image_object.generated_color = (0,0,0,0)
num_pixels = len(coordinateList)

# create an editable copy (list)
pixels = list(image_object.pixels)

def grid(x,y):
    return x + width * y


# Set Point Color
def drawPointColor (x,y,R,G,B,A):
   
    pixelNumber = grid(x,y)*4
   
    pixels[pixelNumber] = R
    pixels[pixelNumber+1] = G
    pixels[pixelNumber+2] = B
    pixels[pixelNumber+3] = A

#Draw Point Color
max = max(len(coordinateList),width)
for i in range(0,max,1):
    j = i % width
    k = i // width
    if i < len(coordinateList):
        R = coordinateList[i][0] # coordinate X = 0
        G = coordinateList[i][1] # coordinate Y = 1
        B = coordinateList[i][2] # coordinate Z = 2
       
        drawPointColor(j,k,R,G,B,1)
        #print(i)
       
# Write back to image.
# Slice notation here means to replace in-place, not sure if it's faster...
image_object.pixels[:] = pixels

# Should probably update image
image_object.update()       
       
#Show result in UV/image Editor
for area in bpy.context.screen.areas :
    if area.type == 'IMAGE_EDITOR' :
            area.spaces.active.image = image_object
           

#DO YOUR OPERATIONS HERE

now = time.time() #Time after it finished

print("Compilation Time: ", now-then, " seconds")


et le résultat:
Image
Avatar de l’utilisateur
GameL
 
Message(s) : 80
Inscription : 06 Sep 2014, 05:12


Retour vers Scripts - Python - OSL

Qui est en ligne ?

Utilisateur(s) parcourant ce forum : Aucun utilisateur inscrit et 3 invité(s)

cron