Transformez plusieurs données numériques d'élévation en une seule image avec Python

Suite de l'article que j'ai écrit plus tôt? Quelque chose comme
"Essayez d'imaginer les données d'altitude du National Land Research Institute avec Python"
Dans cet article, j'aimerais lancer plusieurs fichiers xml et les organiser correctement pour créer une seule image.

Préparation

Cette fois, les données de maillage de n'importe quelle préfecture seront entièrement supprimées.
Sélectionnez et achetez n'importe quel maillage à partir de la page de téléchargement du National Land Research Institute.
https://fgd.gsi.go.jp/download/menu.php

Cliquez sur le bouton "Aller à la sélection de fichier" dans "Informations cartographiques de base Modèle d'élévation numérique" pour passer à l'écran de téléchargement.
Cette fois, j'utiliserai les données de la préfecture d'Osaka.
Veuillez cocher 10 (ligne de contour de la carte topographique) de mailles de 10 m sur le côté gauche.

基盤地図情報ダウンロードサービス

Dans le code écrit dans cet article, les données fournies par le National Land Research Institute sont en échelle de gris telles quelles
En d'autres termes, dans le cas de données de maillage de 10 m, une image en niveaux de gris de 1125 x 750 est générée pour chaque fichier xml, et ils sont disposés un par un pour générer une grande image.
Dans le cas de la préfecture d'Osaka, une grande image stupide de 6x1125px en largeur et 10x750px en hauteur sera générée, il est donc préférable de sélectionner une petite préfecture.
Si vous souhaitez réduire le nombre de pixels dans une seule image, veuillez jouer avec les parties décrites ci-dessous.

En passant, une fois que vous avez répondu au fichier ZIP déposé, je pense qu'il a la structure de données suivante.

 Répertoire décompressé
|-- FG-GML-0000-00-DEM10B.zip
|-- FG-GML-0000-00-DEM10B.zip
|-- etc...

Vous pouvez décompresser chaque fichier ZIP davantage, mais cette fois, il sera traité comme un fichier ZIP car c'est un peu gênant.

Le code entier ressemble à ci-dessous

import os
import re
import sys
import glob
import zipfile
import numpy as np
from PIL import Image
import xml.etree.ElementTree as ET

WIDTH = 1125
HEIGHT = 750

#Préparation
def set_value(dir, rate):
    global WIDTH
    global HEIGHT
    #Répertorier et trier les maillages par nom de fichier
    meshList = []
    for f in glob.glob(os.path.join(dir, "*.zip")):
        base = os.path.basename(f)
        meshList.append(base[7:11] + base[12:14])
    meshList.sort()

    #Nombre de données à traiter
    denominator = len(meshList)
    #Nombre de données traitées
    numerator = 0

    #Examinez le maillage au nord, au sud, à l'est et à l'ouest dans la liste des mailles
    top = right = meshList[-1]
    bottom = left = meshList[0]
    for meshNumber in meshList:
        str(meshNumber)
        if top[0:2] < meshNumber[0:2] or (top[0:2] <= meshNumber[0:2] and top[4] <= meshNumber[4] and top[4] <= meshNumber[4]):
            top = meshNumber
        if bottom[0:2] > meshNumber[0:2] or (bottom[0:2] >= meshNumber[0:2] and bottom[4] >= meshNumber[4]):
            bottom = meshNumber
        if right[2:4] < meshNumber[2:4] or (right[2:4] <= meshNumber[2:4] and right[5] <= meshNumber[5]):
            right = meshNumber
        if left[2:4] > meshNumber[2:4] or (left[2:4] >= meshNumber[2:4] and left[5] >= meshNumber[5]):
            left = meshNumber
    #Obtenez la taille de la toile à partir du maillage final
    vartical = (int(top[0:2])-int(bottom[0:2])) * 8 + int(top[4]) - int(bottom[4]) + 1
    horizon = (int(right[2:4])-int(left[2:4])) * 8 + int(right[5]) - int(left[5]) + 1
    maxArea = vartical * horizon
    point = top[0:2] + left[2:4]  + top[4] + left[5]
    #génération de canevas
    canvas = Image.new('RGB', (int(WIDTH / rate) * horizon, int(HEIGHT / rate) * vartical), (0, 0, 0))

    #Lecture de fichiers et imagerie
    for zipfile in glob.glob(os.path.join(dir, "*.zip")):
        paste_image(zipfile, point, canvas, rate)
        numerator += 1
        print('%d / %d' % (numerator, denominator))
    canvas.save('dem.png', 'PNG', quality=100)


#Méthode d'imagerie
def paste_image(z, p, c, r):
    global WIDTH
    global HEIGHT
    point = p
    canvas = c
    rate = r
    with zipfile.ZipFile(z, "r") as zf:
        for info in zf.infolist():
            inner = info
        with zf.open(inner) as zfile:
            root = ET.fromstring(zfile.read())
            namespace = {
                'xml': 'http://fgd.gsi.go.jp/spec/2008/FGD_GMLSchema',
                'gml': 'http://www.opengis.net/gml/3.2'
            }
            dem = root.find('xml:DEM', namespace)
            #Numéro de maillage
            mesh = dem.find('xml:mesh', namespace).text
            #Nombre de cellules disposées(La valeur réelle est ajoutée par 1)
            high = dem.find('./xml:coverage/gml:gridDomain/gml:Grid/gml:limits/gml:GridEnvelope/gml:high', namespace).text.split(' ')
            highX = int(high[0]) + 1
            highY = int(high[1]) + 1

            #Réglage de la taille de l'image(Le nombre de données==Nombre de pixels)
            dataSize = highX * highY

            #Tableau de données d'altitude
            dem_text = dem.find('./xml:coverage/gml:rangeSet/gml:DataBlock/gml:tupleList', namespace).text
            data = re.findall(',(.*)\n', dem_text)
            dataNp = np.empty(dataSize)
            for i in range(len(data)):
                if(data[i] == "-9999.00"):
                    dataNp[i] = 0
                else:
                    dataNp[i] = float(data[i])

            #Coordonnées de début des données
            startPoint = dem.find('./xml:coverage/gml:coverageFunction/gml:GridFunction/gml:startPoint', namespace).text.split(' ')
            startPointX = int(startPoint[0])
            startPointY = int(startPoint[1])
            startPosition = startPointY * highX + startPointX

            #Lorsque le nombre de données est insuffisant(S'il y a des espaces au-dessus et en dessous de l'image)
            if(len(dataNp) < dataSize):
                add = []
                #Lorsque les données en bas de l'image sont insuffisantes
                if(startPosition == 0):
                    for i in range(dataSize - len(dataNp)):
                        add.append(0)
                    dataNp.extend(add)
                #Lorsque les données en haut et en bas de l'image sont insuffisantes
                else:
                    for i in range(startPosition):
                        add.append(0)
                    dataNp[0:0] = add
                    add = []
                    for i in range(dataSize - len(dataNp) - len(add)):
                        add.append(0)
                    dataNp.extend(add)

            #Conversion d'entiers 8 bits de données
            dataNp = (dataNp / 15).astype(np.uint8)  #Divisez dataNp par 15 pour correspondre au point le plus élevé du mont Fuji à 255
            data = dataNp.reshape(highY, highX)

            #Imagerie des données numériques d'élévation
            pilImg = Image.fromarray(np.uint8(data))
            pilImg = pilImg.resize((int(highX / rate), int(highY / rate)), Image.LANCZOS) # NEAREST

            #Calculer les coordonnées du maillage à coller
            targetX = (int(point[0:2]) - int(mesh[0:2])) * 8 + int(point[4]) - int(mesh[4])
            targetY = (int(mesh[2:4]) - int(point[2:4])) * 8 + int(mesh[5]) - int(point[5])

            canvas.paste(pilImg, (targetY * int(WIDTH / rate), targetX * int(HEIGHT / rate)))

#Entrez le répertoire contenant le fichier ZIP
DIR = sys.argv[1]
RATE = int(sys.argv[2])

set_value(DIR, RATE)

Lors de l'exécution de python, cela devrait fonctionner si vous spécifiez un répertoire plein de fichiers ZIP

Supplément

Où générer un canevas avec la méthode set_value

canvas = Image.new('RGB', (1125 * horizon, 750 * vartical), (0, 0, 0))

Les 1125 et 750 de Coco écrivent chacun simplement manuellement le nombre de cellules dans les données numériques d'élévation.
Étant donné que les valeurs elles-mêmes sont les mêmes que les highX et highY qui apparaissent dans le code, c'est un tracas deux fois, et les highX et Y sont déjà divers codes merdiques tels que la recherche de la valeur chaque fois qu'une image est générée.
(Je vais le réécrire peut-être)
Je suis content que quelqu'un le refactore ... Et

dataNp = (dataNp / 15).astype(np.uint8)

Qu'est-ce que 15? Veuillez vous référer à l'article précédent pour la réponse.
https://qiita.com/artistan/items/99266407702d4152e9d5

Redimensionnons la grande image

Comme je l'ai écrit au début, il n'est pas pratique de générer une grande image avec le code tel qu'il est.
Donc, la partie suivante de la méthode set_value

canvas = Image.new('RGB', (1125 * horizon, 750 * vartical), (0, 0, 0))

De

canvas = Image.new('RGB', (1125/10 * horizon, 750/10 * vartical), (0, 0, 0))

Et redimensionner le pilImage commenté

pilImg = pilImg.resize((int(highX)/ 10, int(highY) / 10), Image.LANCZOS) # NEAREST

Si vous le faites, il sera pratique de générer une image réduite à 1/10.

Enfin

Voici la préfecture d'Osaka, qui a été générée avec le code ci-dessus et réduite de manière appropriée.

dem

Osaka n'est pas intéressante car elle n'a pas beaucoup de hauteur, mais je pense que cela vaut la peine d'être vu dans un endroit plus accidenté.
Sur une échelle de gris, la forme de la montagne ressemble à une nervure de feuille, qui est plutôt fraîche.
Je ne pouvais que l'expliquer incompréhensible, mais merci d'avoir lu.

Recommended Posts

Transformez plusieurs données numériques d'élévation en une seule image avec Python
Transformez les données de vacances en une trame de données avec les pandas
Faites une loterie avec Python
Faisons une interface graphique avec python.
Créer un système de recommandation avec python
Faisons un graphe avec python! !!
Faisons la voix lentement avec Python
Créez un framework Web avec Python! (1)
Créez une application de bureau avec Python avec Electron
Faisons un bot Twitter avec Python!
Créez un framework Web avec Python! (2)
Créez un arbre de décision à partir de 0 avec Python et comprenez-le (4. Structure des données)
Pyinstaller transforme les scripts Python en .exes qui peuvent être exécutés sous Windows
Créer un bot Twitter Trend avec heroku + Python
Je veux faire un jeu avec Python
Essayez de créer un code de "décryptage" en Python
Une histoire sur la gestion des données binaires en Python
Folium: Visualisez les données sur une carte avec Python
Remplaçons UWSC par Python (5) Faisons un robot
Essayez de créer un groupe de dièdre avec Python
Convertir JSON en CSV avec Python de Splunk
Extraire des données d'une page Web avec Python
Combinez des chaînes répétitives en une seule avec des expressions régulières Python.
Analyse de données avec python 2
Obtenez des données financières avec python (puis un peu de bricolage)
[Pratique] Créez une application Watson avec Python! # 2 [Fonction de traduction]
[Pratique] Créez une application Watson avec Python! # 1 [Discrimination linguistique]
Créez un Slackbot simple avec un bouton interactif en python
[Jouons avec Python] Créer un livre de comptes de ménage
Essayez de créer un jeu simple avec Python 3 et iPhone
Faire un point d'arrêt sur la couche c avec python
Remplissez l'arrière-plan d'une seule couleur avec OpenCV2 + Python
Jusqu'à ce que vous insériez des données dans une feuille de calcul en Python
Un serveur qui fait écho aux données POSTées avec flask / python
Créer un outil de formatage CSV avec Python Pandas Py Installer
Qu'est-ce que Dieu? Créez un chatbot simple avec python
[Super facile] Faisons un LINE BOT avec Python.
Analyse de données avec Python
Programme Python qui convertit les données ical en texte
Calcul numérique avec Python
Créons un client de socket Web avec Python. (Authentification par jeton d'accès)
[Pratique] Créez une application Watson avec Python! # 3 [Classification du langage naturel]
Incorporer un interpréteur Python dans une application C ++ avec pybind11 + cmake
J'ai essayé de créer diverses "données factices" avec Python faker
Associez Python Enum à une fonction pour la rendre appelable
Expérimentez pour créer un PDF indépendant pour Kindle avec Python
Créez des applications, enregistrez des données et partagez-les avec un seul e-mail
Technique élégante pour coller des données CSV dans Excel avec Python
[Python] Transformez les ressources AWS simulées avec Moto en appareils Pytest
Exemple de données créées avec python
Obtenez des données Youtube avec python
Créez Puyopuyo AI avec Python
Créer un bookmarklet en Python
Créer un répertoire avec python
Faire un feu avec kdeplot
Lire des données json avec python