การค้นหาบล็อกของเมืองโดยใช้กราฟนั้นไม่น่าแปลกใจเลย โดยทั่วไปจำนวนนี้จะหาชุดที่เล็กที่สุดของวงที่เล็กที่สุด (SSSR) ซึ่งเป็นปัญหาที่สมบูรณ์แบบของ NP ความคิดเห็นของปัญหานี้ (และปัญหาที่เกี่ยวข้อง) สามารถพบได้ที่นี่ ในดังนั้นมีคำอธิบายหนึ่งในขั้นตอนวิธีการแก้ปัญหามันนี่ เท่าที่ฉันสามารถบอกได้ไม่มีการใช้งานที่สอดคล้องกันในnetworkx
(หรือในหลามสำหรับเรื่องนั้น) ฉันลองวิธีนี้ในเวลาสั้น ๆ แล้วก็ละทิ้งมันไป - สมองของฉันไม่ได้เป็นรอยขีดข่วนสำหรับงานประเภทนี้ในวันนี้ ที่ถูกกล่าวว่าฉันจะให้รางวัลแก่ทุกคนที่อาจเข้าชมหน้านี้ในภายหลังและโพสต์การดำเนินการทดสอบอัลกอริทึมที่พบ SSSR ในหลาม
ฉันได้ติดตามแนวทางที่ต่างออกไปแทนที่จะใช้ประโยชน์จากความจริงที่ว่ากราฟรับประกันได้ว่าเป็นภาพถ่าย สั้น ๆ แทนที่จะถือเป็นปัญหากราฟเราถือว่านี่เป็นปัญหาการแบ่งส่วนภาพ ก่อนอื่นเราจะพบภูมิภาคที่เชื่อมต่อทั้งหมดในภาพ จากนั้นเราจะกำหนดรูปร่างรอบ ๆ แต่ละภูมิภาคแปลงรูปร่างในพิกัดภาพกลับเป็นลองจิจูดและละติจูด
รับการนำเข้าและนิยามฟังก์ชันต่อไปนี้:
#!/usr/bin/env python
# coding: utf-8
"""
Find house blocks in osmnx graphs.
"""
import numpy as np
import osmnx as ox
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib.path import Path
from matplotlib.patches import PathPatch
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from skimage.measure import label, find_contours, points_in_poly
from skimage.color import label2rgb
ox.config(log_console=True, use_cache=True)
def k_core(G, k):
H = nx.Graph(G, as_view=True)
H.remove_edges_from(nx.selfloop_edges(H))
core_nodes = nx.k_core(H, k)
H = H.subgraph(core_nodes)
return G.subgraph(core_nodes)
def plot2img(fig):
# remove margins
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
# convert to image
# https://stackoverflow.com/a/35362787/2912349
# https://stackoverflow.com/a/54334430/2912349
canvas = FigureCanvas(fig)
canvas.draw()
img_as_string, (width, height) = canvas.print_to_buffer()
as_rgba = np.fromstring(img_as_string, dtype='uint8').reshape((height, width, 4))
return as_rgba[:,:,:3]
โหลดข้อมูล ทำการแคชการนำเข้าถ้าทำการทดสอบซ้ำ ๆ มิฉะนั้นบัญชีของคุณอาจถูกแบน พูดจากประสบการณ์ที่นี่
G = ox.graph_from_address('Nørrebrogade 20, Copenhagen Municipality',
network_type='all', distance=500)
G_projected = ox.project_graph(G)
ox.save_graphml(G_projected, filename='network.graphml')
# G = ox.load_graphml('network.graphml')
ตัดโหนดและขอบที่ไม่สามารถเป็นส่วนหนึ่งของรอบได้ ขั้นตอนนี้ไม่จำเป็นอย่างเคร่งครัด แต่ส่งผลให้รูปทรงดีกว่า
H = k_core(G, 2)
fig1, ax1 = ox.plot_graph(H, node_size=0, edge_color='k', edge_linewidth=1)
แปลงแปลงเป็นภาพและค้นหาภูมิภาคที่เชื่อมต่อ:
img = plot2img(fig1)
label_image = label(img > 128)
image_label_overlay = label2rgb(label_image[:,:,0], image=img[:,:,0])
fig, ax = plt.subplots(1,1)
ax.imshow(image_label_overlay)
สำหรับแต่ละภูมิภาคที่มีป้ายกำกับให้ค้นหารูปร่างและแปลงพิกัดพิกเซลของรูปร่างกลับไปเป็นพิกัดข้อมูล
# using a large region here as an example;
# however we could also loop over all unique labels, i.e.
# for ii in np.unique(labels.ravel()):
ii = np.argsort(np.bincount(label_image.ravel()))[-5]
mask = (label_image[:,:,0] == ii)
contours = find_contours(mask.astype(np.float), 0.5)
# Select the largest contiguous contour
contour = sorted(contours, key=lambda x: len(x))[-1]
# display the image and plot the contour;
# this allows us to transform the contour coordinates back to the original data cordinates
fig2, ax2 = plt.subplots()
ax2.imshow(mask, interpolation='nearest', cmap='gray')
ax2.autoscale(enable=False)
ax2.step(contour.T[1], contour.T[0], linewidth=2, c='r')
plt.close(fig2)
# first column indexes rows in images, second column indexes columns;
# therefor we need to swap contour array to get xy values
contour = np.fliplr(contour)
pixel_to_data = ax2.transData + ax2.transAxes.inverted() + ax1.transAxes + ax1.transData.inverted()
transformed_contour = pixel_to_data.transform(contour)
transformed_contour_path = Path(transformed_contour, closed=True)
patch = PathPatch(transformed_contour_path, facecolor='red')
ax1.add_patch(patch)
กำหนดจุดทั้งหมดในกราฟต้นฉบับที่อยู่ข้างใน (หรือบน) รูปร่าง
x = G.nodes.data('x')
y = G.nodes.data('y')
xy = np.array([(x[node], y[node]) for node in G.nodes])
eps = (xy.max(axis=0) - xy.min(axis=0)).mean() / 100
is_inside = transformed_contour_path.contains_points(xy, radius=-eps)
nodes_inside_block = [node for node, flag in zip(G.nodes, is_inside) if flag]
node_size = [50 if node in nodes_inside_block else 0 for node in G.nodes]
node_color = ['r' if node in nodes_inside_block else 'k' for node in G.nodes]
fig3, ax3 = ox.plot_graph(G, node_color=node_color, node_size=node_size)
การหาว่าสองบล็อกเป็นเพื่อนบ้านนั้นง่ายหรือไม่ เพียงตรวจสอบว่าพวกเขาแบ่งปันโหนด:
if set(nodes_inside_block_1) & set(nodes_inside_block_2): # empty set evaluates to False
print("Blocks are neighbors.")