See site in english Voir le site en francais
Website skin:
home  download  forum  link  contact

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

Author Topic: Tile Maker - Un outil pour intégrer facilement des tuiles de surface  (Read 13377 times)

0 Members and 1 Guest are viewing this topic.

Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
07 March 2014, 23:53:21
Salut,
Je me suis dernièrement attelé à un petit outil de création de tuiles de surface pour Orbiter, de la manière la plus simple possible.
Elle ne prend pas en charge le téléchargement des images satellites mais vous lui donnez une image, deux coordonnées et Tile Maker vous sort les surface tiles toutes fraîches, converties en DDS*, avec le texte à ajouter à la base pour y placer lesdites tuiles.

Théoriquement, toutes images de toutes tailles y sont acceptés.



Le projet est au stade "même le code est en version alpha", et si les calculs sont pour la plupart bons, il manque le principal, qui est séparer en tuiles et convertir en DDS. Mais j'espère que l'outil aidera ;)

Projet Open Source (C#) : https://tilemaker.codeplex.com/
Lien vers le sujet O-F.com : http://www.orbiter-forum.com/showthread.php?t=33407

Et en nouvelles, je viens juste de finir la correcte implémentation du calcul des longeurs des côtés de l'image.

* La conversion en DDS se fera par nConvert


Offline Fast_toche

  • Legend
  • ******
  • Posts: 1329
  • Country: France fr
  • Karma: 34
  • Time is nothing...
Reply #1 - 08 March 2014, 02:05:36
Chapeau et merci! :wor:


Offline Jim Lovell

  • Global Moderator
  • Legend
  • *****
  • Posts: 1549
  • Country: Belgium be
  • Karma: 39
    • Mon site
Reply #2 - 09 March 2014, 00:39:42
Oooooh !!  :love:
Superbe !
C'est exactement ce que j'avais imaginé en prototype il y a quelques temps :



Hâte d'essayer ça !

Jim Love:love:LL
C'est en se plantant que l'on construit ses racines....


ConneXion

Offline Fast_toche

  • Legend
  • ******
  • Posts: 1329
  • Country: France fr
  • Karma: 34
  • Time is nothing...
Reply #3 - 09 March 2014, 00:44:42
Cha mérite des caramels euh pardon, des karmas cha non? :)


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #4 - 09 March 2014, 13:04:06
Hey Jim,
Avais-tu codé quelque peu ce projet? Je cherche un moyen d'avoir le niveau des tuiles au niveau maximum.
Aussi, si l'utilisateur cherche à fare des tuiles dans des levels différents, comment gérer ça? Je veux dire, est-ce que une tuile de 1024px en level 3 (par exemple) correspond à 4 tuiles en level 4 ?


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #5 - 09 March 2014, 17:53:44
Des nouvelles:
Mon "Tile Splitter" threadé fonctionne à merveille!


Je lui donne l'image de base, une aire à couper, le chemin du futur fichier (avec bien sur la fonction pour découper), il envoie tout ça dans un Thread Pool, et ce pour chaque tuile.
Le test que j'ai fait m'a utilisé 55% de mon CPU en moyenne, pour une durée de 6 secondes. Pas mal!


Comme vous le voyez, l'image originale fait 10752x6912, et les 273 tuiles prédites y sont bien. Cela montre que de relativement grandes images sont bien "mangées", et avec rapidité, ce qui veut dire qu'une aire plus grande / plus détaillée est facilement couvrable avec TileMaker.
Maintenant il manque juste les informations à l'utilisateur, parce que on ne sait pas ce qu'il se passe dans le GUI pour l'instant.

Je suis content ! :)


Offline Fox-Terrier

  • League of
  • Legend
  • ******
  • Posts: 1426
  • Country: Switzerland ch
  • Karma: 28
  • :D
Reply #6 - 09 March 2014, 19:52:41
ça en jette !!  :)

Et monsieur fait du multitreading en prime ! :fool:

C'est quoi la suite ? Coder en CUDA pour que la carte graphique NVIDIA bosse aussi ? :bug:
C'est grosso-modo du C, avec des spécificités pour faire la différence entre ce que fait le CPU et le GPU
Vu ton niveau, ce sera fait en un clin d'oeil ! :badsmile:


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #7 - 09 March 2014, 20:07:12
Pourquoi pas? :badsmile:

Quelqu'un aurait-il un moyen de savoir en quel niveau les tuiles sont? C'est le dernier "problème" auquel je fais face avant de pouvoir correctement nommer mes fichier de la même manière que orbiter les reçoit.


Offline Jim Lovell

  • Global Moderator
  • Legend
  • *****
  • Posts: 1549
  • Country: Belgium be
  • Karma: 39
    • Mon site
Reply #8 - 09 March 2014, 20:55:57
Hey Jim,
Avais-tu codé quelque peu ce projet? Je cherche un moyen d'avoir le niveau des tuiles au niveau maximum.

Malheureusement non, c'était un prototype d'interface que j'avais réalisé lorsque Dan avait sorti son base tile maker.

Bon en ce qui concerne Cuda, pas sur que ça vaille l'investissement en code, il faut une carte assez puissante et surtout, Nvidia. Du coup toutes les ati -->  :badfinger:

C'est cool que tu utilises les threads, j'ai découvert ça aussi récemment et c'est assez marrant de faire travailler plusieurs processus ensemble. Le tout est de ne pas faire "freezer" l'interface principale pendant qu'un processus est en cours.

Concernant le tile level, peut-être peux-tu regarder par rapport à la définition de l'image ? Une image en 2048*2048 qui couvre soit 5 soit 10 km^2 (au pif hein) pourrait changer de level. Mais là je ne peux pas vraiment t'aider.

Jim Love:love:LL
C'est en se plantant que l'on construit ses racines....


ConneXion

Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #9 - 09 March 2014, 21:08:34
Je me suis amusé pendant la boucle d'attente à montrer le nombre de threads en train de tourner, avec un Stopwatch qui montre le temps passé. Du coup je me retrouve avec un nombre qui change constamment, variant entre 3 et 15 ^^

Apparement la longueur d'une tuile pour un niveau est fixé, donc je n'ai qu'à comparer la valeur contre celle de la tuile et trouver le niveau correspondant.
La question et: quelles sont ces fameuses longueurs ?

Aussi, le plus dur reste à faire: "s'agripper" à la grille du niveau correspondant et renommer les tuiles de la façon dont Orbiter les aime.

Là j'aurais besoin d'aide en experts du tuilage de carreaux Orbiter.


Et pour CUDA, je rigolais évidemment, absolument aucune utilité pour cette app.


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #10 - 09 March 2014, 21:17:59
Concernant le tile level, peut-être peux-tu regarder par rapport à la définition de l'image ? Une image en 2048*2048 qui couvre soit 5 soit 10 km^2 (au pif hein) pourrait changer de level. Mais là je ne peux pas vraiment t'aider.

Je fais déjà, je montre la résolution en mètre par pixel (ou cm/px, ou mm/px, ça dépends de la résolution), mais je pense pas que ce soit vraiment sur ceci que l'on puisse se fier pour avoir un numéro de niveau ...


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #11 - 09 March 2014, 22:35:34
Eh bah en fait, ce true, cet algorythme multi-thread tout joli, bah il se peut que ce soit à chier complet ...  :sad:
J'ai pris cette image comme exemple (car c'est plaisant, c'est la première image trouvée, puis les asiatiques elles sont trop belles.... enfin je m'emporte)


L'image à des dimensions 4096x4096, donc 64 tiles. Eh bien:


Comme vous le voyez, il y a bien 64 tiles, mais il y a un hic, c'est que l'image à du être redimensionnée avant le tuilage ... Les tuiles montrent une Hannah (c'est le nom de la fille) décalée, alors qu'elle est normalement au centre de l'image !
Donc j'ai vérifié mon code. Ligne par ligne. J'y ai presque gueulé dessus. Mais non rien. J'ai même expliqué mon code à un alien imaginaire pour qu'il compenne, mais on a tout les deux tout compris, et j'ai toujours pas trouvé le problème.
Je pense qu'au final ce bien beau truc multithreading, bah ça fout la merde. Encore une nuit et 2-3 tasses de café inutilement dépensées ...
Voici le lien vers le code dont je parle, pour ceux qui veulent s'aventurer dans du code: https://tilemaker.codeplex.com/SourceControl/latest#Threaded.cs


Offline florian6973

  • Full Member
  • ***
  • Posts: 80
  • Karma: 8
Reply #12 - 10 March 2014, 09:39:34
J'ai regardé ton code, et je l'ai modifié pour essayer de résoudre ce problème. :wall: En cherchant sur internet, j'ai trouvé aussi plein de petits codes qui m'ont permis de le résoudre.

Voici le code, tu pourras si tu veux remettre les threads :) :
Code: [Select]
        void Split(Bitmap Input, int tilelength)
        {
            int cols = (int)Math.Truncate((float)Input.Width / (float)tilelength);
            int rows = (int)Math.Truncate((float)Input.Height / (float)tilelength);
            int rowpad = (rows - 1).ToString().Length;
            int colpad = (cols - 1).ToString().Length;
            string filepath = System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, UniqueID.GetNewID());
            Directory.CreateDirectory(filepath);
            for (int r = 0; r < rows; r++)
            {
                for (int c = 0; c < cols; c++)
                {
                    string name = String.Format("r{1}c{0}.bmp", c.ToString().PadLeft(colpad, '0'), r.ToString().PadLeft(rowpad, '0'));
                    string fName = System.IO.Path.Combine(filepath, name);
                    Rectangle rz = new Rectangle(c * tilelength,
                                                r * tilelength,
                                                tilelength,
                                                tilelength);
                    Bitmap bmpCrop = Input.Clone(rz, System.Drawing.Imaging.PixelFormat.DontCare);
                    bmpCrop.Save(fName);
                    Application.DoEvents();
                }
            }
            Status.Text = "Finish !";
        }
En espérant t'avoir aidé !  ;)

[EDIT by Jim] Balises code rajoutées pour plus de lisibilité ;)
[Edit] => Merci de les avoir rajoutées, je ne savais pas qu'elles existaient ! :wor:

« Last Edit: 10 March 2014, 10:09:07 by florian6973 »

Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #13 - 10 March 2014, 12:59:23
Ce "PixelFormat.DontCare" qui change tout!
Merci florian6973, je teste tout ça !


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #14 - 10 March 2014, 13:06:22
En fait, "PixelFormat.DontCare" ne résoud rien. Mais ta version du code m'a fait penser à une autre façon d'agencer le code. Au boulot, SolarLiner!


Offline Fox-Terrier

  • League of
  • Legend
  • ******
  • Posts: 1426
  • Country: Switzerland ch
  • Karma: 28
  • :D
Reply #15 - 10 March 2014, 13:16:27
Juste comme ça : s'il y avait quelque chose plus à droite, est-ce que ça s’effacerait ? Ou est-ce que ça apparait à gauche ?


Offline florian6973

  • Full Member
  • ***
  • Posts: 80
  • Karma: 8
Reply #16 - 10 March 2014, 13:21:13
Je n'ai effectivement pas compris d'où venait l'erreur, mais en modifiant le code de façon à utiliser une autre méthode le rend fonctionnel. Grâce à une méthode qui marche, j'ai modifié ton code ;) (il peut rester quelques erreurs).

Code: [Select]
        void CropAndSave(object state)
        {
            try
            {
                object[] State = state as object[];
                Bitmap Input = (Bitmap)State[0];
                Rectangle r = (Rectangle)State[1];
                string filename = (string)State[2];
                Bitmap bmpCrop = Input.Clone(r, System.Drawing.Imaging.PixelFormat.DontCare);
                bmpCrop.Save(filename);
            }
            finally
            {
                lock (_ActiveWorkersLock)
                {
                    --_CountOfActiveWorkers;
                    Monitor.PulseAll(_ActiveWorkersLock);
                }
            }
        }
       
        void Split(Bitmap Input, int tilelength)
        {
            try
            {
                if (!Miscallenous.IsPowerOfTwo((ulong)tilelength)) throw new ArgumentException("Tile Length must be power of two");
                Status.Text = "Thread Pool started. Booting up operations ...";
                sw.Restart();
                int cols = (int)Math.Truncate((float)Input.Width / (float)tilelength);
                int rows = (int)Math.Truncate((float)Input.Height / (float)tilelength);
                int rowpad = (rows - 1).ToString().Length;
                int colpad = (cols - 1).ToString().Length;
                string filepath = System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, UniqueID.GetNewID());
                Directory.CreateDirectory(filepath);
                for (int r = 0; r < rows; r++)
                {
                    for (int c = 0; c < cols; c++)
                    {
                        string name = String.Format("r{1}c{0}.bmp", c.ToString().PadLeft(colpad, '0'), r.ToString().PadLeft(rowpad, '0'));
                        string fName = System.IO.Path.Combine(filepath, name);
                        Rectangle rect = new Rectangle(c * tilelength,
                                                    r * tilelength,
                                                    tilelength,
                                                    tilelength);
                        lock (_ActiveWorkersLock)
                            ++_CountOfActiveWorkers;
                        System.Threading.ThreadPool.QueueUserWorkItem(new WaitCallback(CropAndSave), new object[] { Input.Clone(), rect, fName });
                        Status.Text = String.Format("{3:00} thread{4} running. | Elapsed {0:00}:{1:00}:{2:000}", Math.Truncate(sw.Elapsed.TotalMinutes), sw.Elapsed.Seconds, sw.Elapsed.Milliseconds,
                                                                                                                                    _CountOfActiveWorkers, _CountOfActiveWorkers == 1 ? "" : "s");   
                        Application.DoEvents();
                    }
                }
                lock (_ActiveWorkersLock)
                {
                    while (_CountOfActiveWorkers > 0)
                    {
                        Status.Text = String.Format("{3:00} thread{4} running. | Elapsed {0:00}:{1:00}:{2:000}", Math.Truncate(sw.Elapsed.TotalMinutes), sw.Elapsed.Seconds, sw.Elapsed.Milliseconds,
                                                                                                                                    _CountOfActiveWorkers, _CountOfActiveWorkers == 1 ? "" : "s");
                        Application.DoEvents();
                        Monitor.Wait(_ActiveWorkersLock);
                    }
                }
                sw.Stop();
                Status.Text = "Image tiling finished. Takes " + Miscallenous.GetDirectorySize(filepath) / (1024 * 1024) + " Mb. | " + String.Format("Elapsed {0:00}:{1:00}:{2:000}", Math.Truncate(sw.Elapsed.TotalMinutes), sw.Elapsed.Seconds, sw.Elapsed.Milliseconds);
                Process.Start(filepath);
            }
            catch (Exception e)
            {
                MessageBox.Show("Erreur :\n" + e.Message, "ERREUR !", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

Je ne sais pas s'il existe d'autres méthodes plus intéressantes, mais celle utilisée ci-dessus fonctionne à merveille chez moi. :love:

Edit : le bug est peut-être aux anciennes dimensions du Rectangle 'rect' lors de l'initialisation ? :wonder:


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #17 - 10 March 2014, 13:26:08
Oui, ce serait effacé. Tout simplement pas pris en compte par le tuilage.

La méthode florian marche à merveille maintenant! Seulement les threads se bloquent les uns les autres pour l'instant donc aucun intérêt pour le multithreading.


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #18 - 10 March 2014, 14:16:05
Il semble the Input.Clone() bloque le thread principal pour une raison ou pour une autre. Bizzare ...


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #19 - 10 March 2014, 15:12:43
WINNING !!!
Ce qui posait problème pour le "SaveAndCrop", c'est le DPI. Certaines images ont un DPI de 72 alors que le par défaut c'est 96. Bitmap prend ça en compte lors du redimensionnement/rognage et du coup, l'image partait en couilles. Mais plus maintenant! Lors du rognage, j'ai copié les paramètres de l'ancien Bitmap vers le nouveau, et plus aucun problème!


Offline Fox-Terrier

  • League of
  • Legend
  • ******
  • Posts: 1426
  • Country: Switzerland ch
  • Karma: 28
  • :D
Reply #20 - 10 March 2014, 16:22:58
Et ben bravo ! :friend:


Offline elphifou

  • Full Member
  • ***
  • Posts: 71
  • Country: France fr
  • Karma: 8
Reply #21 - 26 March 2014, 18:51:00
Bravo !  ;)   karma +1 d'avance  pour t'encourager  :)


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #22 - 27 March 2014, 18:46:53
Ho!
J'avais un peu délaissé ce projet, faute de temps, et envie de m'amuser un peu aussi (je serai fouetté en place publique demain sous les premiers rayons du soleil! M'enfin, touchez pas à mon karma, hein :badsmile: )

J'ai donc toujours ce problème avec TileMaker de level et de calcul de placement de tuiles. Je vais donc ouvrir un topic demandant tout les détails des tuiles d'Orbiter, pour en avoir le cœur net, savoir comment ça marche dans les détails, etc.
En espérant que je récolte plus d'informations sur le sujet!


Offline SolarLiner

  • Global Moderator
  • Legend
  • *****
  • Posts: 2769
  • Country: France fr
  • Karma: 55
  • a été remercié par Le Créateur
Reply #23 - 12 April 2014, 20:41:59
Salut,
Le projet avance, et plutôt bien. Jusqu'au moment où il faut que "j'attache" la photo à la grille des tuiles et ça merdouille par là.
Le but, c'est de créer un rectangle qui représentera la surface totale qu'occupera les tuiles une fois découpés, et pour cela il faut que je convertisse des coordonnées GPS en pixels par rapport à l'image (j'ai tout ce qu'il me faut: résolution en px/cm, px/° ...). Pour ceux qui n'ont pas trop compris (je sais, j'explique pas bien du tout ^^), voici un image:

Le rectangle vert est le rectangle "accroché" à la grille des tuiles, et qui servira pour découper proprement l'image, le rectangle rouge est l'image en elle-même, et la grille est en noire.

J'ai essayé de plusieurs façons différentes, mais ne suis jamais parvenu à un résultat concluant.
A l'aide! Merci d'avance :beer:


Offline Fox-Terrier

  • League of
  • Legend
  • ******
  • Posts: 1426
  • Country: Switzerland ch
  • Karma: 28
  • :D
Reply #24 - 13 April 2014, 18:16:29
tu peux utiliser de la transparence ? comme ça toute tes cases gardent la même taille, et tu peux former le rectangle que tu veux

Je réponds, mais en réalité j'ai pas compris ta question :)