我在底部进行了编辑,发现了新问题(为什么没有加拿大和Shapely和Pyproj的不可靠性)
尽管这种方法并没有完全解决问题,但我认为这种态度比使用pyproc和Shapely更具潜力。如果您将来需要制作更多的ASCII艺术品,这种方法将为您提供更多的可能性和灵活性。首先,我将列出优缺点。
PS:起初我想在您的代码中找到问题,但是我在运行它时遇到了一些pyproj返回的错误。
优点
1)我能够提取所有点(加拿大确实缺失)并旋转图像
2)处理速度非常快,因此可以创建
动画ASCII艺术品。
3)打印一次完成,无需循环
缺点(已知问题,可解决)
1)这种方法明显不能正确地转换地理坐标-太平面了,应该看起来更球形
2)我没有花时间去尝试找到填充边界的解决方案,因此只有边界上有“*”。因此,这种方法需要找到算法来填充国家。我认为这不应该是问题,因为JSON文件包含分离的国家。
3) 除了numpy之外,您还需要两个额外的库 - opencv(您可以使用PIL代替)和Colorama,因为我的示例是动画的,我需要通过将光标移动到(0,0)来“清除”终端而不是使用os.system('cls')
4) 我只使其在python 3中运行。在python 2中也可以工作,但我遇到了sys.stdout.buffer错误
将终端上的字体大小调整到最低点,以便打印的字符适合终端。字体越小,分辨率越高
动画应该看起来像地图正在“旋转”
![enter image description here](https://istack.dev59.com/UhXri.webp)
我使用了一点你的代码来提取数据。步骤在注释中
import json
import sys
import numpy as np
import colorama
import sys
import time
import cv2
if len(sys.argv)>1:
terminal_size = (int(sys.argv[1]),int(sys.argv[2]))
else:
terminal_size=(230,175)
with open('world-countries.json') as f:
countries = []
minimal = 0
maximal = 0
for feature in json.load(f)['features']:
indexes = np.int16(np.array(feature['geometry']['coordinates'][0])*2)
if indexes.min()<minimal:
minimal = indexes.min()
if indexes.max()>maximal:
maximal = indexes.max()
countries.append(indexes)
countries = (np.array(countries)+np.abs(minimal))
correction = np.abs(minimal)
colorama.init()
def move_cursor(x,y):
print ("\x1b[{};{}H".format(y+1,x+1))
move = 0
for i in range(1000):
image = np.zeros(shape=[maximal+correction+1,maximal+correction+1])
move -=1
for i in countries:
if len(i.shape)==2:
image[i[:,1],i[:,0]+move]=255
if len(i.shape)==3:
image[i[0][:,1],i[0][:,0]+move]=255
cut = np.where(image==255)
if move == -1:
max_x,min_x = cut[0].max(),cut[0].min()
max_y,min_y = cut[1].max(),cut[1].min()
new_image = image[min_x:max_x,min_y:max_y]
new_image= new_image[::-1]
new_image = cv2.resize(new_image,terminal_size)
ascii = np.chararray(shape = new_image.shape).astype('|S4')
ascii[:,:]=''
ascii[:,-1]='\n'
new_image[:,-1]=0
ascii[np.where(new_image>0)]='*'
move_cursor(0,0)
sys.stdout.buffer.write(ascii)
time.sleep(0.025)
也许解释一下代码中的主要算法会更好。我喜欢尽可能使用numpy。整个过程就是假装图像(或者在你的情况下是地理坐标)中的坐标是矩阵索引。我有两个矩阵 - 真实图像和作为掩模的Charray。然后,我取出真实图像中有趣像素的索引,并将任何想要的字母分配给Charray掩模中相同索引的位置。由于这样,整个算法不需要一个循环。
关于未来的可能性
假设您还将拥有关于地形(海拔)的信息。让我们说您以某种方式创建了世界地图的灰度图像,其中灰度色阶表示海拔高度。这样的灰度图像将具有形状x,y。您将准备一个形状为[x,y,256]的
3D 矩阵。对于3D矩阵中的256个图层中的每个图层,都会分配一个字母'....;;;;#等'来表示灰度色阶。
当您准备好后,可以获取您的灰度图像,其中任何像素实际上都具有3个坐标:x,y和灰度值。因此,您将从您的灰度地图图像中提取
3个索引数组-> x,y,shade。您的新charray将只是从带有图层字母的
3D矩阵中提取的内容,因为:
x,y = grayscale.shape
3Dmatrix = np.chararray(shape = [x,y,256])
table = ' ......;;;;;;;
for i in range(256):
3Dmatrix[:,:,i] = table[i]
x_indexes = np.arange(x*y)
y_indexes = np.arange(x*y)
chararray_image = np.chararray(shape=[x,y])
...
shades = grayscale.reshape(x*y)
chararray_image[:,:] = 3Dmatrix[(x_indexes ,y_indexes ,shades)].reshape(x,y)
由于此过程中没有循环并且可以一次性打印chararray,因此您实际上可以使用巨大的FPS将电影打印到终端中。
例如,如果您有旋转地球的镜头,您可以制作类似于这样的东西 - (250 * 70个字母),渲染时间为0.03658秒。
![enter image description here](https://istack.dev59.com/9EHdt.webp)
你当然可以在终端中将其提高到极致,实现超分辨率,但是结果的帧率并不好:0.23157秒,大约4-5 FPS。有趣的是,这个帧率非常高,但终端无法处理打印,因此这个低帧率是由于终端的限制而不是计算的限制,因为这个高分辨率的计算只需要0.00693秒,即144 FPS。
![enter image description here](https://istack.dev59.com/C1IMe.webp)
重要修改 - 与上面的某些陈述相矛盾
我不小心打开了原始的json文件,发现加拿大和俄罗斯都有完全正确的坐标。 我犯了一个错误,依赖于我们两个都没有在结果中看到加拿大,所以我认为我的代码没问题。在JSON内部,数据具有不同的非统一结构。俄罗斯和加拿大有“多边形”,因此您需要对其进行迭代。
这意味着什么? 不要依赖Shapely和pyproj。显然,它们无法提取一些国家,如果它们不能可靠地执行此操作,则不能指望它们执行更复杂的操作。
修改代码后,一切正常
代码:这是如何正确加载文件的方式
...
with open('world-countries.json') as f:
countries = []
minimal = 0
maximal = 0
for feature in json.load(f)['features']:
for k in range((len(feature['geometry']['coordinates']))):
indexes = np.int64(np.array(feature['geometry']['coordinates'][k]))
if indexes.min()<minimal:
minimal = indexes.min()
if indexes.max()>maximal:
maximal = indexes.max()
countries.append(indexes)
...
![enter image description here](https://istack.dev59.com/BpH5K.webp)