1 回答

TA貢獻1942條經驗 獲得超3個贊
我在底部進行編輯,發現新問題(為什么沒有加拿大和Shapely和Pyproj的不可靠性)
盡管它不能完全解決問題,但我相信這種態度比使用 pyproc 和 Shapely 更有潛力,并且在未來,如果你做更多的 Ascii 藝術,會給你更多的可能性和靈活性。首先我會寫優點和缺點。
PS:最初我想在您的代碼中找到問題,但是我在運行它時遇到了問題,因為 pyproj 返回了一些錯誤。
優點
1)我能夠提取所有點(加拿大確實缺少)并旋轉圖像
2)處理速度非常快,因此您可以創建動畫 Ascii 藝術。
3)打印一次完成,無需循環
缺點(已知問題,可解決)
1)這種態度顯然不能正確轉換地理坐標 - 太平面了,它應該看起來更球形
2)我沒有花時間試圖找出填充邊框的解決方案,所以只有邊框有'*'。因此這種態度需要找到算法來填充國家。我認為這不應該是問題,因為 JSON 文件包含分隔的國家
3)除了 numpy - opencv(您可以使用 PIL 代替)和 Colorama 之外,您還需要 2 個額外的庫,因為我的示例是動畫的,我需要通過將光標移動到 (0,0) 而不是使用 os.system( 'cls')
4)我讓它只在python 3 中運行。在 python 2 中它也可以工作,但我在使用 sys.stdout.buffer 時遇到錯誤
將終端上的字體大小更改為最低點,以便打印的字符適合終端。字體更小,分辨率更高
動畫應該看起來像地圖在“旋轉”
我用了一點你的代碼來提取數據。步驟在評論中
import json
import sys
import numpy as np
import colorama
import sys
import time
import cv2
#understand terminal_size as how many letters in X axis and how many in Y axis. Sorry not good name
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 # This can be dangerous. Expecting negative values
maximal = 0 # Expecting bigger values than 0
for feature in json.load(f)['features']: # getting data - I pretend here, that geo coordinates are actually indexes of my numpy array
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)) # Transform geo-coordinates to image coordinates
correction = np.abs(minimal) # because geo-coordinates has negative values, I need to move it to 0 - xaxis
colorama.init()
def move_cursor(x,y):
print ("\x1b[{};{}H".format(y+1,x+1))
move = 0 # 'rotate' the globe
for i in range(1000):
image = np.zeros(shape=[maximal+correction+1,maximal+correction+1]) #creating clean image
move -=1 # you need to rotate with negative values
# because negative one are by numpy understood. Positive one will end up with error
for i in countries: # VERY STRANGE,because parsing the json, some countries has different JSON structure
if len(i.shape)==2:
image[i[:,1],i[:,0]+move]=255 # indexes that once were geocoordinates now serves to position the countries in the image
if len(i.shape)==3:
image[i[0][:,1],i[0][:,0]+move]=255
cut = np.where(image==255) # Bounding box
if move == -1: # creating here bounding box - removing empty edges - from sides and top and bottom - we need space. This needs to be done only once
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] # the bounding box
new_image= new_image[::-1] # reverse, because map is upside down
new_image = cv2.resize(new_image,terminal_size) # resize so it fits inside terminal
ascii = np.chararray(shape = new_image.shape).astype('|S4') #create container for asci image
ascii[:,:]='' #chararray contains some random letters - dunno why... cleaning it
ascii[:,-1]='\n' #because I pring everything all at once, I am creating new lines at the end of the image
new_image[:,-1]=0 # at the end of the image can be country borders which would overwrite '\n' created one step above
ascii[np.where(new_image>0)]='*' # transforming image array to chararray. Better to say, anything that has pixel value higher than 0 will be star in chararray mask
move_cursor(0,0) # 'cleaning' the terminal for new animation
sys.stdout.buffer.write(ascii) # print into terminal
time.sleep(0.025) # FPS
也許最好解釋一下代碼中的主要算法是什么。我喜歡盡可能使用 numpy。整件事是我假裝圖像中的坐標,或者它可能是什么(在你的情況下地理坐標)是矩陣索引。然后我有 2 個矩陣 - Real Image 和 Charray 作為掩碼。然后我在真實圖像中獲取有趣像素的索引,并為 Charray Mask 中的相同索引分配我想要的任何字母。多虧了這一點,整個算法不需要一個循環。
關于未來的可能性
想象一下,您還將獲得有關地形(高度)的信息。假設您以某種方式創建了世界地圖的灰度圖像,其中灰色陰影表示高度。這種灰度圖像的形狀為 x,y。您將準備形狀 = [x,y,256] 的3Dmatrix。對于 3D 矩陣中 256 個層中的每一層,您分配一個字母“....;;;;### 等等”來表示陰影。準備好后,您可以拍攝灰度圖像,其中任何像素實際上都有 3 個坐標:x、y 和陰影值。因此,您將從灰度地圖圖像中獲得3 個索引數組-> x,y,shade。您的新 charray 將簡單地提取帶有圖層字母的3Dmatrix,因為:
#Preparation phase
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])
# Ready to print
...
shades = grayscale.reshape(x*y)
chararray_image[:,:] = 3Dmatrix[(x_indexes ,y_indexes ,shades)].reshape(x,y)
因為這個過程沒有循環,你可以一次打印chararray,你實際上可以以巨大的FPS將電影打印到終端
例如,如果你有地球旋轉的鏡頭,你可以制作這樣的東西 -(250*70 個字母),渲染時間 0.03658s
您當然可以將其發揮到極致并在您的終端中實現超分辨率,但由此產生的 FPS 并不是那么好:0.23157s,大約是 4-5 FPS。有趣的是,這種態度FPS是巨大的,但終端根本無法處理打印,所以這種低FPS是由于終端的限制而不是計算的限制,因為這種高分辨率的計算需要0.00693s,即144 FPS。
與上述某些陳述相矛盾
我不小心打開了原始 json 文件,發現有 CANADA 和 RUSSIA 具有完全正確的坐標。我錯誤地依賴于結果中我們都沒有加拿大的事實,所以我希望我的代碼沒問題。在 JSON 中,數據具有不同的 NOT-UNIFIED 結構。俄羅斯和加拿大有“Multipolygon”,因此您需要對其進行迭代。
這是什么意思?不要依賴 Shapely 和 pyproj。顯然他們不能提取一些國家,如果他們不能可靠地做到這一點,你不能指望他們做任何更復雜的事情。
修改代碼后,一切正常
代碼:這是正確加載文件的方法
...
with open('world-countries.json') as f:
countries = []
minimal = 0
maximal = 0
for feature in json.load(f)['features']: # getting data - I pretend here, that geo coordinates are actually indexes of my numpy array
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)
...
添加回答
舉報