Bonjour à tous! Ce message s'adresse particulièrement aux personnes qui ont utilisés la libe57 (je pense qu'il y en a pas beaucoup ... ). En regardant le tutoriel j'ai réussi à lire et écrire des fichiers. Mais maintenant j'ai un problème de taille, c'est à dire que j'essaie de lire un fichier qui fait 50Go, et dans le tutoriel, ils font des
std::vector.resize(x);
à tout va. En gros y'a 1 vector pour X, un pour Y, un pour Z, un pour l'intensité et 3 pour la couleur (rouge, vert, bleu). Sauf que chacun à la taille du nombre de points que j'ai (et j'ai plusieurs milliards de points). Donc forcement j'ai un bad_alloc un moment. (Je précise que le e57 est un scan unique apres avoir été unifié).
Ce que j'aimerai faire c'est pouvoir lire par petit morceaux les points, donc par exemple, je reserve num_points_total / 8, je lis tous ces points, je les écris dans un fichier (par exemple), puis je lis les num_points_total / 8 points suivant et je continue jusqu'a la fin. ça m'éviterait de devoir devoir resize sur des nombres beaucoup trop grand...
Mais je ne trouve pas de moyen de faire. Est-ce que ça se joue sur la fonction
ReadData3DGroupsData // Qui me renvoie que le fait que j'ai 1 seul group a chaque fois...
?
Voilà le code que j'essaie d'utiliser actuellement si jamais ... (mais je ne suis pas sûr que ce soit utile)
void main(){
{
e57::Reader eReader(_name);
eReader.GetE57Root(rootHeader);
guid = rootHeader.guid;
coordinateMetadata = rootHeader.coordinateMetadata;
e57::Data3D scanHeader;
int scanIndex = 0;
eReader.ReadData3D(scanIndex, scanHeader);
int64_t nColumn, nRow, nPoints, nGroupsSize, nCountsSize;
bool bColumnIndex = false;
eReader.GetData3DSizes(scanIndex, nRow, nColumn, nPoints, nGroupsSize, nCountsSize, bColumnIndex);
int cpt = 4;
nRow = nPoints;
nColumn = 1;
nRow = nRow / cpt;
nGroupsSize = cpt;
int64_t nSize = nRow;
std::vector<int8_t> isInvalidData;
if (scanHeader.pointFields.cartesianInvalidStateField) {
isInvalidData.resize(nSize);
}
std::vector<double> xData, yData, zData;
xData.resize(nSize);
yData.resize(nSize);
zData.resize(nSize);
std::vector<double> intData;
double intRange = 0;
double intOffset = 0;
intData.resize(nSize);
intRange = scanHeader.intensityLimits.intensityMaximum - scanHeader.intensityLimits.intensityMinimum;
intOffset = scanHeader.intensityLimits.intensityMinimum;
std::vector<uint16_t> redData, greenData, blueData;
int32_t colorRedRange = 1;
int32_t colorRedOffset = 0;
int32_t colorGreenRange = 1;
int32_t colorGreenOffset = 0;
int32_t colorBlueRange = 1;
int32_t colorBlueOffset = 0;
redData.resize(nSize);
greenData.resize(nSize);
blueData.resize(nSize);
colorRedRange = scanHeader.colorLimits.colorRedMaximum - scanHeader.colorLimits.colorRedMinimum;
colorRedOffset = scanHeader.colorLimits.colorRedMinimum;
colorGreenRange = scanHeader.colorLimits.colorGreenMaximum - scanHeader.colorLimits.colorGreenMinimum;
colorGreenOffset = scanHeader.colorLimits.colorGreenMinimum;
colorBlueRange = scanHeader.colorLimits.colorBlueMaximum - scanHeader.colorLimits.colorBlueMinimum;
colorBlueOffset = scanHeader.colorLimits.colorBlueMinimum;
std::vector<int64_t> idElementValue;
std::vector<int64_t> startPointIndex;
std::vector<int64_t> pointCount;
if (nGroupsSize > 0)
{
idElementValue.resize(nGroupsSize);
startPointIndex.resize(nGroupsSize);
pointCount.resize(nGroupsSize);
for (int i = 0; i < nGroupsSize; ++i) {
startPointIndex[i] = (nPoints / cpt) * i;
pointCount[i] = nPoints / cpt;
idElementValue[i] = (nPoints / cpt) * i;
}
if (!eReader.ReadData3DGroupsData(scanIndex, nGroupsSize, idElementValue.data(),
startPointIndex.data(), pointCount.data()))
nGroupsSize = 0;
}
std::vector<int32_t>rowIndex;
std::vector<int32_t>columnIndex;
rowIndex.resize(nSize);
columnIndex.resize(nSize);
int compteur = 0;
std::ofstream writed("e57/Writed.xyz");
while (compteur < cpt) {
e57::CompressedVectorReader dataReader = eReader.SetUpData3DPointsData(
compteur, //!< data block index given by the NewData3D
nRow, //!< size of each of the buffers given
xData.data(), //!< pointer to a buffer with the x data
yData.data(), //!< pointer to a buffer with the y data
zData.data(), //!< pointer to a buffer with the z data
isInvalidData.data(), //!< pointer to a buffer with the valid indication
intData.data(), //!< pointer to a buffer with the lidar return intesity
NULL,
redData.data(), //!< pointer to a buffer with the color red data
greenData.data(), //!< pointer to a buffer with the color green data
blueData.data(), //!< pointer to a buffer with the color blue data
NULL,
NULL,
NULL,
NULL,
NULL,
rowIndex.data(), //!< pointer to a buffer with the rowIndex
columnIndex.data() //!< pointer to a buffer with the columnIndex
);
int64_t count = 0;
unsigned size = 0;
int col = 0;
int row = 0;
while (size = dataReader.read())
{
//std::cout << dataReader.read() << std::endl;
for (long i = 0; i < size; i++)
{
if (columnIndex.data())
col = columnIndex[i];
else
col = 0; //point cloud case
if (rowIndex.data())
row = rowIndex[i];
else
row = count; //point cloud case
writed << xData[i] << " " << yData[i] << " " << zData[i];
//Normalize intensity to 0 - 1.
double intensity = (intData[i] - intOffset) / intRange;
writed << " " << intData[i] << '\n';
//Normalize color to 0 - 255
//int red = ((redData[i] - colorRedOffset) * 255) / colorRedRange;
//int green = ((greenData[i] - colorGreenOffset) * 255) / colorBlueRange;
//int blue = ((blueData[i] - colorBlueOffset) * 255) / colorBlueRange;
//writed << " " << red << " " << green << " " << blue << '\n';
count++;
}
}
compteur++;
dataReader.close();
}
}
P.S : Oui, je n'ai pas fais tous les tests préconisés, parceque j'aimerai d'abord réussir à faire ce que je veux et qu'avec mon fichier test, je sais qu'il n'y a pas de problèmes. Pour le moment, ça écris 4 fois les même point dans mon fichier "writed"
- Edité par KirbXCoucou 9 novembre 2018 à 10:30:27
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. » D. Mendeleïev
!!!!!!!!!!!! C'est compilé en 64bits! Mais par contre, je savais pas qu'on pouvais étendre la taille maximale du swap!! Comment fait-on ça? On peut le faire en script?
- Edité par KirbXCoucou 9 novembre 2018 à 12:39:48
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. » D. Mendeleïev
Pour résumer: tu peut faire du memory mapping avec mmap par exemple. Tu retrouve le même principe sur de l'envoie CPU-GPU.
Au delà de lire le fichier et de le charger en RAM, compte tu faire un rendu graphique aussi ? Car là tu vas te retrouver avec la même problématique coté VRAM.
Pour moi c'est un peu le principe d'un lecteur vidéo, on se ballade dans un fichier, on décompresse une ou plusieurs frames (dans ton cas pas, on lirais juste) et on les upload sur le GPU. Du coup ton bottleneck par exemple serait la lecture le disque du coup tu pourrais faire du buffering si tu ne veut pas que ton rendu rame (tu prendrais des frames d'avance). Pour ce qui est de l'upload coté GPU là il y a d'autre tactique. Mais bon je m'étale pas sachant que je ne sais même pas si tu vas faire du rendu graphique.
Je m'avance un peu bien sur, mais souvent quand on a un point cloud on a bien envie de le voir :-)
Après, il faut aussi peut-être réfléchir sur les algorithmes pour ne pas avoir à gérer simultanément toutes les données.
Pour l'approche bourrin du découpage de fichier, on passe au problème de fichiers à records de taille variable + taille des header + ..., donc si on n'a qu'un truc one-shot pour prétraiter les données, pas la peine de faire de la "rocket science".
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Un fichier de 50 Go ? Est ce qu'il est exploitable ?
Je te prends un exemple, imaginons un logiciel 3D qui contient un objet 3D analytique, je veux le discrétiser en triangles, ou en points.
Je donne au logiciel un paramètre de discrétisation : plus il est élevé, plus le logiciel me découpera mon modèle en triangles plus fins, ou avec un nuage de points plus serré.
Et théoriquement, rien ne m'empêche de pousser le paramétrage jusqu'à faire des milliards de triangles/points... et des fichiers de 50 Go...
Mais des fichiers qu'aucun des logiciels ne relira. Un résultat inexploitable, un non sens....
Est ce qu'on n'est pas dans ce cas la pour ton exemple ?
Un fichier de 50 Go ? Est ce qu'il est exploitable ?
Je te prends un exemple, imaginons un logiciel 3D qui contient un objet 3D analytique, je veux le discrétiser en triangles, ou en points.
Je donne au logiciel un paramètre de discrétisation : plus il est élevé, plus le logiciel me découpera mon modèle en triangles plus fins, ou avec un nuage de points plus serré.
Et théoriquement, rien ne m'empêche de pousser le paramétrage jusqu'à faire des milliards de triangles/points... et des fichiers de 50 Go...
Mais des fichiers qu'aucun des logiciels ne relira. Un résultat inexploitable, un non sens....
Est ce qu'on n'est pas dans ce cas la pour ton exemple ?
Cela m'intéresse beaucoup ce que tu dis !
Un use case que je vois et dont je ne connais pas vraiment la solution, je serai super intéressé à avoir des pistes @Fvirtman si tu en as.
J'aimerais faire un streamer qui va calculer à partir d'un frustum de camera quel partie du fichier charger et affichuer. Je peut charger un frustum plus large que mon point de vue pour bufferiser par exemple. Ou comme tu le décris et comme on le fait souvent en tesselation, un paramètre de discrétisation.
Mon problème c'est plutôt comment définir quel chunk du fichier aller charger ? Un fichier comme le format décrit par l'OP est structuré spatialement ? Est-ce que c'est de ça dont tu parler quand tu dis "exploitable" ? Peut-on imaginer une passe de pré-processing du fichier que l'on fait qu'une seule fois ?
Il me semble qu'on ne parle pas de la même chose mais tu lances un débat intéressant.
Moi je parlais par exemple, dans un logiciel de CAO, tu fais un cylindre... un simple cylindre. Mathématiquement, c'est parfaitement rond.
Si tu veux l'exporter en un format tessellé, donc une approximation du cylindre fait en triangles, tu va définir un paramètre de tessellation.
Si tu es radin, tu peux te dire, "allez, on va mettre un paramètre de telle sorte mon cylindre soit finalement approximé en une extrusion d'octogone (un cylindre est l'extrusion d'un cercle). Donc tu auras 8 faces rectangulaires, chacune faite de 2 triangles, donc une approximation grossière de 16 triangles.
Si tu veux quelque chose de plus fin, tu va approximer le cercle et faire donc une tessellation plus fine. si tu coupes ton cercle en, allez, 50 morceaux, tu auras déjà un beau cylindre parfaitement approximé.
Mais rien ne t'empêche de couper le cercle en 1000, 1 million, 1 milliard, pour approximer le cercle et faire un fichier tessellé de plusieurs Go. Un simple cylindre de 50 Go .... Et ça, c'est stupide, inutile, et inexploitable.
Et c'est la personne qui a entré le paramétrage en amont au moment de la sauvegarde qui a fait n'importe quoi.
Evidemment, le cylindre est le cas le plus simple, mais même avec une pièce plus complexe, avoir des fichiers de 50 Go, n'est ce pas avoir clairement abusé ? Bref.
Sinon, ce dont tu parles est intéressant, il concernerait un monde immense, donc forcément fait de beaucoup beaucoup de triangles, et la, il faut avoir structuré le monde. Il existe plein de techniques pour ça, il y a les chunks de voxels comme Minecraft, le BSP comme Quake et pas mal de FPS, et l'octree un peu moins complexe que le BSP mais diablement puissant aussi !
Mais l'idée est déjà que le fichier d'entrée ne soit pas fait n'importe comment.
Tout à fait, mais l'octree est un structure de donnée qui finalement te permet d'indexer l'espace. Mais cela implique d'avoir un octree de construit quelque part. Du coup je me demandais si il y avait des format de fichier déjà structuré et meme avec une API qui permet de se ballader spatialement dans le fichier.
On pourrais envisager de stocker l'octree directement dans le fichier :
Le fichier serait ainsi séparé en 8 blocs, quand on charge le fichier, au lieu de charger tout le fichier, on charge l'offset et la taille du bloc. Et quand on veut parcourir une branche, chaque bloc est a nouveau recoupé en 8 blocs, récursivement.
Donc en mémoire, au lieu de tout avoir, on a des branches "non chargées" qui contiennent uniquement l'offset et la taille de la zone d'en dessous si on veut la charger.
Toute la difficulté revient à savoir quand charger un bloc, jusqu'où, et surtout lequel décharger si on commence à avoir la mémoire bien remplie
Et sinon en ce qui concerne les BSP, dans les bons vieux FPS d'antan, les fichiers étaient déjà structurés en BSP : on chargeait directement le BSP ! (mais on chargeait tout)...
Je précise que c'est des nuages de points et pas des fichiers CAO, hein ! Pas question de triangles ici, mais bien juste de points (d'où le poids des fichiers.. )
Mais non ! Alors je suis sur téléphone et je peux pas répondre à tout, ça serai trop long. Mais là librairie libe57 ne permet pas (à mon sens, et c'est pour cela que je pose la question) de lire par chunck ! Mais j'aimerai en être sûr.
Pour ce qui est de la taille des fichiers, on travaille avec des logiciels qui permettent d'ouvrir ces gros fichiers, mais qui ne sont que peu efficaces sur les filtres de nuage de points. En appliquant mes filtres perso, je réduis la taille des fichiers par un facteur 5/10, ce qui est vraiment utile pour la suite.
Bref, non, je ne crée pas des fichiers inexploitable, et ce que je pensais faire, si je pouvais lire par chunck est de créer un octree de fichier (le temps de calcul importe assez peu finalement, d'abord un truc qui marche, ensuite on verra pour optimiser) , ou je stocke mes points dans des fichiers, et puis je travail sur chaque fichier séparer.
Et si je demandais si il était possible de changer la taille du swap en script, c'est que y'a pas que 1 ordi qui va exploiter ce programme,, mais plusieurs sont destinés, alors j'ai pas envie de devoir modifier tous les ordis. Ducoup si je peux le faire en script je le mets plus grand au début, puis je le redescend à la fin
Voila voilà
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. » D. Mendeleïev
Du coup, je me demande, est ce que tes fichiers, c'est juste une liste de points en vrac ? (et donc des milliards ?)
Ils sont ordonnés ou alors peuvent arriver dans n'importe quel ordre ?
Je ne sais plus si c'est toi qui parlait il y a quelques semaines d'un format de fichier assez simple a lire (celui la ?) est ce que le fichier est simple à lire ? Car manifestement, ta lib ne permet pas de lire qu'une partie des données, donc si c'est pas trop dur, réinvente la roue pour rouler à un endroit qui n'est pas prévu ! (donc charge pas paquets)
EDIT : Et si c'était toi, j'ai retrouvé ton intervention.
Du coup, ton fichier était d'un format très simple à priori ! Avais tu essayé la méthode dont je parle ici ?
En fait, entre temps j'ai eu une demande pour changer de format de fichier. Avant j'utilisais un fichier PTX, c'est un fichier dans lesquels les points sont tous écrit en brut dans un fichier texte. L'ordre n'avait une espece d'importance pour certains logiciels mais pas pour moi.
La on me demande d'utiliser des fichiers e57 qui est un format un peu plus compliqué, et il faut utiliser la libe57 pour pouvoir les utiliser (enfin, c'est une grande aide). Il va peut-être falloir que je réinvente la roue pour essayé de charger par bloc, chose que je n'ai pas l'impression qu'il est possible de faire actuellement :( Mais je sais même pas si c'est possible de le faire en réalité. Je pense que oui, mais le seul logiciel que j'ai vu qui arrive à ouvrir de si gros fichiers de points est celui qu'on utilise dans mon entreprise, mais je comprends pas comment il fait (Et si je dois moi aussi pouvoir l'ouvrir, c'est que ce logiciel n'offre des possibilités que très limitée :()
Merci pour vos aides
- Edité par KirbXCoucou 12 novembre 2018 à 8:34:37
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. » D. Mendeleïev
J'ai les fichiers .cpp et .h de la lib, oui! Mais je t'avoue que je pense pas avoir les capacité pour pouvoir gérer ça dans un temps raisonnable seul actuellement. Je voulais d'abord savoir si quelqu'un avait déjà planché la dessus avant de m'y mettre moi même. Mais il semblerait que je vais y arriver un moment ou l'autre...
EDIT : En fait, je crois qu'il existe la fonction
void seek (int64_t recordNumber);
qui à pour description
Set record number of CompressedVectorNode where next read will start.
Parameters:
[in]recordNumber The index of record in ComressedVectorNode where next read using this CompressedVectorReader will start.
qui ferait le taf je crois, mais le corps de la fonction c'est ça :
GG @KirbXCoucou, t'as rapidement localiser un "working in progress" dans le projet.
C'est clairement la fonction qu'il te faut pour lire des "records" par tranche. Mais s'il n'a pas été implémenté directement, c'est que l'implémentation n'est pas trivial.
Avant de chercher à scripter l'élargissement du swap, il faut déjà vérifier que la solution fonctionne. Je viens d'apprendre que le type de licence peu influencer la taille maximale de la mémoire virtuelle :
Je vais aller lire ça! Merci beaucoup! J'ai demandé aux créateurs de la lib (enfin, j'ai ouvert un tiquet), mais le fait que la dernière MaJ date de 2012 me laisse un peu perplexe pour le coup... M'enfin! On verra! Yes! Commande Shell plutôt que directement dans le c++, c'est sûr que ça doit être plus évident! Je vais tester tout ça! merci beaucoup!
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. » D. Mendeleïev
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. »
D. Mendeleïev
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. »
D. Mendeleïev
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. »
D. Mendeleïev
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. »
D. Mendeleïev
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. »
D. Mendeleïev
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
« Je n’ai pas besoin de preuve. Les lois de la nature, contrairement aux lois de la grammaire, ne permettent aucune exception. »
D. Mendeleïev