mapnik generate_tiles.py возвращает ошибку памяти
Я пытаюсь создать плитки с использованием generate_tiles.py, и каждый раз, когда я запускаю скрипт, я получаю следующую ошибку:
Исключение в потоке Thread-2: Traceback (последний вызов был последним): файл "/usr/lib/python2.7/threading.py", строка 552, в файле __bootstrap_inner self.run () "/ usr / lib / python2. 7 / threading.py ", строка 505, в прогоне self.__target(*self.__args, **self.__kwargs) Файл"render_tiles.py", строка 114, в цикле self.render_tile(tile_uri, x, y, z) Файл "render_tiles.py", строка 96, в render_tile mapnik.render(self.m, im) MemoryError
Вот мой сценарий.
#! / USR / бен / питон из математического импорта пи, потому что, грех, журнал, опыт, Атан из вызова импорта подпроцесса import sys, os из очереди импорт картник импорт потоков импортировать случайный импортировать argparse custom_fonts_dir = '/usr/share/fonts/' mapnik.register_fonts(custom_fonts_dir) DEG_TO_RAD = pi/180 RAD_TO_DEG = 180/ пи # Количество рендеринга потоков по умолчанию должно быть примерно равно количеству доступных процессорных ядер. NUM_THREADS = 4 def minmax (a,b,c): а = макс (а, б) а = мин (а, в) вернуть Класс GoogleProjection: def __init__(self,level =18): self.Bc = [] self.Cc = [] self.zc = [] self.Ac = [] с = 256 для d в диапазоне (0, уровни): е = с /2; self.Bc.append(с /360.0) self.Cc.append(c/(2 * pi)) self.zc.append((е, е)) self.Ac.append(с) с *= 2 def fromLLtoPixel(self,ll,zoom): d = self.zc[int(zoom)] e = round(d[0] + float(ll[0]) * self.Bc[zoom]) f = minmax(sin(DEG_TO_RAD * float(ll[1])),-0,99999,99999) g = round(d[1] + 0.5*log((1+f)/(1-f))*-self.Cc[увеличить]) возврат (е, г) def fromPixelToLL(self,px,zoom): e = self.zc[увеличить] f = (px[0] - e[0])/self.Bc[увеличить] g = (px[1] - e[1])/-self.Cc[увеличить] h = RAD_TO_DEG * ( 2 * атан (exp (г)) - 0,5 * пи) возврат (f, h) Класс RenderThread: def __init__(self, tile_dir, mapfile, q, printLock, maxZoom): self.tile_dir = tile_dir self.q = q self.m = mapnik.Map(256, 256) self.printLock = printLock # Загрузить стиль XML mapnik.load_map(self.m, mapfile) # Получить проекцию self.prj = mapnik.Projection(self.m.srs) # Проецирование между пиксельными координатами плитки и LatLong (EPSG:4326) self.tileproj = GoogleProjection(maxZoom+1) def render_tile(self, tile_uri, x, y, z): # Рассчитать позиции пикселей внизу слева и вверху справа p0 = (x * 256, (y + 1) * 256) p1 = ((x + 1) * 256, y * 256) # Конвертировать в латлонг (EPSG:4326) l0 = self.tileproj.fromPixelToLL(p0, z); l1 = self.tileproj.fromPixelToLL(p1, z); # Преобразовать в картографическую проекцию (например, Mercator Coords EPSG:900913) c0 = self.prj.forward(mapnik.Coord(l0[0],l0[1])) c1 = self.prj.forward(mapnik.Coord(l1[0],l1[1])) # Ограничительная коробка для плитки if hasattr(mapnik,'mapnik_version') и mapnik.mapnik_version() >= 800: bbox = mapnik.Box2d(c0.x,c0.y, c1.x,c1.y) еще: bbox = mapnik.Envelope(c0.x,c0.y, c1.x,c1.y) render_size = 256 self.m.resize(render_size, render_size) self.m.zoom_to_box(BBOX) self.m.buffer_size = 128 # Рендеринг изображения с помощью Agg Renderer по умолчанию im = mapnik.Image(render_size, render_size) mapnik.render(self.m, im) im.save(tile_uri, 'png256') Цикл def (self): пока верно: # Получить плитку из очереди и визуализировать ее r = self.q.get () если (г == нет): self.q.task_done() перерыв еще: (name, tile_uri, x, y, z) = r существует = "" если os.path.isfile(tile_uri): существует = "существует" еще: self.render_tile(tile_uri, x, y, z) байт =os.stat(tile_uri)[6] пусто = '' если байт == 103: empty = "Пустая плитка" self.printLock.acquire() напечатать имя, ":", z, x, y, существует, пусто self.printLock.release() self.q.task_done() def render_tiles(bbox, mapfile, tile_dir, minZoom=1,maxZoom=18, name="unknown", num_threads=NUM_THREADS): print "render_tiles(",bbox, mapfile, tile_dir, minZoom, maxZoom, name,")" # Запуск потоков рендеринга очередь = очередь (32) printLock = threading.Lock() renderers = {} для меня в диапазоне (num_threads): renderer = RenderThread(tile_dir, mapfile, очередь, printLock, maxZoom) render_thread = threading.Thread(target=renderer.loop) render_thread.start() #print "Запущен поток визуализации%s" % render_thread.getName() renderers[i] = render_thread если не os.path.isdir(tile_dir): os.mkdir(tile_dir) gprj = GoogleProjection(maxZoom+1) ll0 = (bbox[0],bbox[3]) ll1 = (bbox[2],bbox[1]) для диапазона z (minZoom,maxZoom + 1): px0 = gprj.fromLLtoPixel(ll0,z) px1 = gprj.fromLLtoPixel(ll1,z) печать "fromlattolon" # проверить, есть ли у нас каталоги на месте zoom = "%s" % z если нет os.path.isdir(tile_dir + zoom): os.mkdir(tile_dir + zoom) для диапазона х (int(px0[0]/256.0),int(px1[0]/256.0)+1): # Подтвердить координату х если (x = 2**z): Продолжить # проверить, есть ли у нас каталоги на месте str_x = "%s" % x если нет os.path.isdir(tile_dir + zoom + '/' + str_x): os.mkdir(tile_dir + zoom + '/' + str_x) для y в диапазоне (int(px0[1]/256.0),int(px1[1]/256.0)+1): # Подтвердить координату х если (у = 2 ** г): Продолжить str_y = "%s" % y tile_uri = tile_dir + zoom + '/' + str_x + '/' + str_y + '.png' # Отправить плитку для рендеринга в очередь t = (имя, tile_uri, x, y, z) queue.put(т) # Сигнал рендеринга потоков для выхода, отправив пустой запрос в очередь для меня в диапазоне (num_threads): queue.put(отсутствует) # ожидание ожидающих завершения задач рендеринга queue.join() для меня в диапазоне (num_threads): рендереры [I].join() if __name__ == "__main__": MIN_LON = '29.5732'; MAX_LON = '35.0360'; MIN_LAT = '-1.4840'; MAX_LAT = '4.2144'; bbox = ( MIN_LON, MIN_LAT,MAX_LON, MAX_LAT) style_file="/ главная /mossplix/ проекты /Dev/ MapIt/ карта / статический /tilemill/uganda_districts.xml" tile_dir="/ главная /mossplix/ проекты /UnicefDev/ MapIt/ карта / статический / плитка /" min_zoom=7 MAX_ZOOM =14 render_tiles(bbox, style_file, tile_dir, min_zoom, max_zoom)
Вот конфигурационный файл mapnik, конфигурационный файл mapnik, а вот шейп- файл. Я скомпилировал мапник из исходного кода, так что должно быть хорошо. В чем может быть проблема?
2 ответа
Я могу сказать, что это generate_tiles.py
первоначально, слегка измененный.
Ошибка MemoryError указывает, что вы либо запрашиваете ненормально большое изображение для рендеринга, либо обнаружили ошибку Mapnik.
Поскольку первое более вероятно, я полагаю, что вы допустили ошибку во время изменения generate_tiles.py
, Поэтому я взял ваш скрипт, переписал последнюю версию в svn и получил различия: https://gist.github.com/1197587.
На линии № 106 и № 115 вы, вероятно, хотите использовать ==
не =
потому что в противном случае вы создаете очень большие значения x и y, которые являются недопустимыми и могут быть причиной очень больших запросов изображения (которые являются неправильными для данной плитки).
Количество потоков рендеринга по умолчанию, которые должны быть порождены, должно быть примерно равно количеству доступных ядер ЦП. NUM_THREADS = 4
У меня была точно такая же ошибка с NUM_THREADS=4. Измените значение по умолчанию NUM_THREADS на 1. У меня i5 (4 ядра /1 поток на ядро), а NUM_THREADS = 4 очень нестабильно. С NUM_THREADS = 1 работает нормально. Если он работает с NUM_THREADS = 1, попробуйте с NUM_THREADS=2 и NUM_THREADS=3, если ничего не произошло.