Add legacy support
This commit is contained in:
210
networks/legacy_roads/Skeleton.py
Normal file
210
networks/legacy_roads/Skeleton.py
Normal file
@@ -0,0 +1,210 @@
|
||||
import numpy as np
|
||||
import skan
|
||||
from skimage.morphology import skeletonize
|
||||
from skan.csr import skeleton_to_csgraph
|
||||
from collections import Counter
|
||||
from PIL import Image
|
||||
import random
|
||||
|
||||
from gdpc import Editor
|
||||
|
||||
|
||||
class Skeleton:
|
||||
def __init__(self):
|
||||
self.lines = []
|
||||
self.intersections = []
|
||||
self.centers = []
|
||||
self.graph = []
|
||||
self.coordinates = []
|
||||
|
||||
def setSkeleton(self, data):
|
||||
binary_skeleton = skeletonize(data)
|
||||
|
||||
graph, coordinates = skeleton_to_csgraph(binary_skeleton)
|
||||
self.graph = graph.tocoo()
|
||||
|
||||
# List of lists. Inverted coordinates.
|
||||
coordinates = list(coordinates)
|
||||
print(coordinates)
|
||||
for i in range(len(coordinates)):
|
||||
coordinates[i] = list(coordinates[i])
|
||||
|
||||
print(coordinates)
|
||||
coordinates_final = []
|
||||
|
||||
for i in range(len(coordinates[0])):
|
||||
print((coordinates[0][i], coordinates[1][i], coordinates[2][i]))
|
||||
coordinates_final.append(
|
||||
(coordinates[0][i], coordinates[1][i], coordinates[2][i]))
|
||||
|
||||
self.coordinates = coordinates_final
|
||||
|
||||
def findNextElements(self, key):
|
||||
"""Find the very nearest elements"""
|
||||
|
||||
line = []
|
||||
|
||||
values = np.array(self.graph.row)
|
||||
indices = np.where(values == key)[0]
|
||||
|
||||
for i in range(len(indices)):
|
||||
if self.graph.row[indices[i]] == key:
|
||||
line.append(self.graph.col[indices[i]])
|
||||
return line
|
||||
|
||||
def findLine(self, key):
|
||||
nextKeys = self.findNextElements(key)
|
||||
|
||||
if len(nextKeys) >= 3: # Intersections.
|
||||
return nextKeys
|
||||
|
||||
if len(nextKeys) == 2 or len(nextKeys) == 1: # In line or endpoints.
|
||||
line = []
|
||||
line.append(key)
|
||||
line.insert(0, nextKeys[0])
|
||||
if len(nextKeys) == 2:
|
||||
line.insert(len(line), nextKeys[1])
|
||||
|
||||
nextKeys = line[0], line[-1]
|
||||
|
||||
while len(nextKeys) == 2 or len(nextKeys) == 1:
|
||||
extremity = []
|
||||
for key in nextKeys:
|
||||
nextKeys = self.findNextElements(key)
|
||||
|
||||
if len(nextKeys) <= 2:
|
||||
# Add the neighbors that is not already in the line.
|
||||
for element in nextKeys:
|
||||
if element not in line:
|
||||
extremity.append(element)
|
||||
line.append(element)
|
||||
|
||||
if len(nextKeys) >= 3:
|
||||
# Add the intersection only.
|
||||
extremity.append(key)
|
||||
|
||||
nextKeys = []
|
||||
for key in extremity:
|
||||
ends = self.findNextElements(key)
|
||||
if len(ends) == 2:
|
||||
nextKeys.append(key)
|
||||
return line
|
||||
|
||||
def parseGraph(self):
|
||||
for key, value in sorted(
|
||||
Counter(self.graph.row).items(), key=lambda kv: kv[1], reverse=True
|
||||
):
|
||||
# Start from the biggest intersections.
|
||||
if value != 2: # We don't want to be in the middle of a line.
|
||||
line = self.findLine(key)
|
||||
|
||||
# We have now all the connected points if it's an
|
||||
# intersection. We need to find the line.
|
||||
|
||||
if value != 1:
|
||||
# It's not an endpoint.
|
||||
self.centers.append(key)
|
||||
self.intersections.append(line)
|
||||
for i in line:
|
||||
line = self.findLine(i)
|
||||
|
||||
if i in line:
|
||||
# The key is inside the result : it's a line.
|
||||
alreadyInside = False
|
||||
for l in self.lines:
|
||||
# Verification if not already inside.
|
||||
if Counter(l) == Counter(line):
|
||||
alreadyInside = True
|
||||
# print(line, "inside", lines)
|
||||
|
||||
if alreadyInside == False:
|
||||
self.lines.append(line)
|
||||
else:
|
||||
# The key is not inside the result, it's an
|
||||
# intersection directly connected to the key.
|
||||
line = [key, i]
|
||||
alreadyInside = False
|
||||
for l in self.lines:
|
||||
# Verification if not already inside.
|
||||
if Counter(l) == Counter(line):
|
||||
alreadyInside = True
|
||||
# print(line, "inside", lines)
|
||||
|
||||
if alreadyInside == False:
|
||||
self.lines.append(line)
|
||||
|
||||
def map(self):
|
||||
"""
|
||||
|
||||
Generate an image to visualize 2D path of the skeleton.
|
||||
|
||||
Returns:
|
||||
image: 2D path of the skeleton on top of the heightmap.
|
||||
"""
|
||||
editor = Editor()
|
||||
|
||||
buildArea = editor.getBuildArea()
|
||||
buildRect = buildArea.toRect()
|
||||
xzStart = buildRect.begin
|
||||
xzDistance = (max(buildRect.end[0], buildRect.begin[0]) - min(buildRect.end[0], buildRect.begin[0]), max(
|
||||
buildRect.end[1], buildRect.begin[1]) - min(buildRect.end[1], buildRect.begin[1]))
|
||||
|
||||
heightmap = Image.open("data/heightmap.png").convert('RGB')
|
||||
roadsArea = Image.new("L", xzDistance, 0)
|
||||
width, height = heightmap.size
|
||||
|
||||
# Lines
|
||||
for i in range(len(self.lines)):
|
||||
r, g, b = (random.randint(0, 255), random.randint(
|
||||
0, 255), random.randint(0, 255))
|
||||
|
||||
for j in range(len(self.lines[i])):
|
||||
|
||||
z = self.coordinates[self.lines[i][j]][0]
|
||||
y = self.coordinates[self.lines[i][j]][1]
|
||||
x = self.coordinates[self.lines[i][j]][2]
|
||||
|
||||
heightmap.putpixel(
|
||||
(
|
||||
int(z),
|
||||
int(x),
|
||||
),
|
||||
(r + j, g + j, b + j),
|
||||
)
|
||||
|
||||
roadsArea.putpixel(
|
||||
(
|
||||
int(z),
|
||||
int(x),
|
||||
),
|
||||
(255),
|
||||
)
|
||||
|
||||
# Centers
|
||||
for i in range(len(self.centers)):
|
||||
print(self.coordinates[self.centers[i]])
|
||||
heightmap.putpixel(
|
||||
(int(self.coordinates[self.centers[i]][0]), int(
|
||||
self.coordinates[self.centers[i]][2])),
|
||||
(255, 255, 0),
|
||||
)
|
||||
|
||||
roadsArea.putpixel(
|
||||
(int(self.coordinates[self.centers[i]][0]), int(
|
||||
self.coordinates[self.centers[i]][2])),
|
||||
(255),
|
||||
)
|
||||
|
||||
# # Intersections
|
||||
# for i in range(len(self.intersections)):
|
||||
# intersection = []
|
||||
# for j in range(len(self.intersections[i])):
|
||||
# intersection.append(self.coordinates[self.intersections[i][j]])
|
||||
|
||||
# for i in range(len(intersection)):
|
||||
# heightmap.putpixel(
|
||||
# (int(self.intersections[i][2]), int(self.intersections[i][0])),
|
||||
# (255, 0, 255),
|
||||
# )
|
||||
|
||||
return heightmap, roadsArea
|
||||
Reference in New Issue
Block a user