예제 #1
0
    def get_datasource(self, logger):
        bbox = self._mercator_bbox

        dst_bbox = bbox.bounds
        dst_x_size = self.size
        dst_y_size = self.size

        dst_srs = osr.SpatialReference()
        dst_srs.ImportFromEPSG(3857)

        dst_drv = gdal.GetDriverByName("MEM")
        dst_ds = dst_drv.Create('', dst_x_size, dst_y_size, 1, gdal.GDT_Float32)

        dst_x_res = float(dst_bbox[2] - dst_bbox[0]) / dst_x_size
        dst_y_res = float(dst_bbox[3] - dst_bbox[1]) / dst_y_size
        dst_gt = (dst_bbox[0], dst_x_res, 0,
                  dst_bbox[3], 0, -dst_y_res)
        dst_ds.SetGeoTransform(dst_gt)
        dst_ds.SetProjection(dst_srs.ExportToWkt())
        dst_ds.GetRasterBand(1).SetNoDataValue(FLT_NODATA)

        # figure out what the approximate scale of the output image is in
        # lat/lon coordinates. this is used to select the appropriate filter.
        ll_bbox = self.latlon_bbox()
        ll_x_res = float(ll_bbox.bounds[2] - ll_bbox.bounds[0]) / dst_x_size
        ll_y_res = float(ll_bbox.bounds[3] - ll_bbox.bounds[1]) / dst_y_size

        composite.compose(self, dst_ds, logger, min(ll_x_res, ll_y_res))

        try:
            yield dst_ds

        finally:
            del dst_ds
예제 #2
0
파일: skadi.py 프로젝트: tilezen/joerd
    def render(self, tmp_dir):
        logger = logging.getLogger('skadi')

        bbox = _bbox(self.x, self.y)

        mid_dir = os.path.join(tmp_dir, self.output_dir,
                               ("N" if self.y >= 90 else "S") +
                               ("%02d" % abs(self.y - 90)))
        if not os.path.isdir(mid_dir):
            try:
                os.makedirs(mid_dir)
            except OSError as e:
                # swallow the error if the directory exists - it's
                # probably another thread creating it.
                if e.errno != errno.EEXIST or not os.path.isdir(mid_dir):
                    raise

        tile = _tile_name(self.x, self.y)
        hgt_file = os.path.join(mid_dir, tile + ".hgt")
        tile_file = os.path.join(mid_dir, tile + ".hgt.gz")
        logger.info("Generating tile %r..." % tile)

        dst_bbox = bbox.bounds
        dst_x_size = 3601
        dst_y_size = 3601

        dst_srs = osr.SpatialReference()
        dst_srs.ImportFromEPSG(4326)

        # for SRTM, must first buffer in memory, then write to disk with
        # CreateCopy.
        dst_drv = gdal.GetDriverByName("MEM")
        dst_ds = dst_drv.Create('', dst_x_size, dst_y_size, 1, gdal.GDT_Int16)
        dst_x_res = float(dst_bbox[2] - dst_bbox[0]) / dst_x_size
        dst_y_res = float(dst_bbox[3] - dst_bbox[1]) / dst_y_size
        dst_gt = (dst_bbox[0], dst_x_res, 0,
                  dst_bbox[3], 0, -dst_y_res)
        dst_ds.SetGeoTransform(dst_gt)
        dst_ds.SetProjection(dst_srs.ExportToWkt())
        dst_ds.GetRasterBand(1).SetNoDataValue(-32768)

        composite.compose(self, dst_ds, logger, min(dst_x_res, dst_y_res))

        logger.debug("Writing SRTMHGT: %r" % hgt_file)
        srtm_drv = gdal.GetDriverByName("SRTMHGT")
        srtm_ds = srtm_drv.CreateCopy(hgt_file, dst_ds)

        del dst_ds
        del srtm_ds

        logger.debug("Compressing HGT -> GZ: %r" % tile_file)
        with gzip.open(tile_file, 'wb') as gz, open(hgt_file, 'rb') as hgt:
            shutil.copyfileobj(hgt, gz)

        os.remove(hgt_file)
        assert os.path.isfile(tile_file)

        logger.info("Done generating tile %r" % tile)
예제 #3
0
파일: skadi.py 프로젝트: isikl/joerd
    def render(self, tmp_dir):
        logger = logging.getLogger('skadi')

        bbox = _bbox(self.x, self.y)

        mid_dir = os.path.join(tmp_dir, self.output_dir,
                               ("N" if self.y >= 90 else "S") +
                               ("%02d" % abs(self.y - 90)))
        if not os.path.isdir(mid_dir):
            try:
                os.makedirs(mid_dir)
            except OSError as e:
                # swallow the error if the directory exists - it's
                # probably another thread creating it.
                if e.errno != errno.EEXIST or not os.path.isdir(mid_dir):
                    raise

        tile = _tile_name(self.x, self.y)
        hgt_file = os.path.join(mid_dir, tile + ".hgt")
        tile_file = os.path.join(mid_dir, tile + ".hgt.gz")
        logger.info("Generating tile %r..." % tile)

        dst_bbox = bbox.bounds
        dst_x_size = 3601
        dst_y_size = 3601

        dst_srs = osr.SpatialReference()
        dst_srs.ImportFromEPSG(4326)

        # for SRTM, must first buffer in memory, then write to disk with
        # CreateCopy.
        dst_drv = gdal.GetDriverByName("MEM")
        dst_ds = dst_drv.Create('', dst_x_size, dst_y_size, 1, gdal.GDT_Int16)
        dst_x_res = float(dst_bbox[2] - dst_bbox[0]) / dst_x_size
        dst_y_res = float(dst_bbox[3] - dst_bbox[1]) / dst_y_size
        dst_gt = (dst_bbox[0], dst_x_res, 0, dst_bbox[3], 0, -dst_y_res)
        dst_ds.SetGeoTransform(dst_gt)
        dst_ds.SetProjection(dst_srs.ExportToWkt())
        dst_ds.GetRasterBand(1).SetNoDataValue(-32768)

        composite.compose(self, dst_ds, logger, min(dst_x_res, dst_y_res))

        logger.debug("Writing SRTMHGT: %r" % hgt_file)
        srtm_drv = gdal.GetDriverByName("SRTMHGT")
        srtm_ds = srtm_drv.CreateCopy(hgt_file, dst_ds)

        del dst_ds
        del srtm_ds

        logger.debug("Compressing HGT -> GZ: %r" % tile_file)
        with gzip.open(tile_file, 'wb') as gz, open(hgt_file, 'rb') as hgt:
            shutil.copyfileobj(hgt, gz)

        os.remove(hgt_file)
        assert os.path.isfile(tile_file)

        logger.info("Done generating tile %r" % tile)
예제 #4
0
파일: normal.py 프로젝트: wgruzek/joerd
    def render(self, tmp_dir):
        logger = logging.getLogger('normal')

        bbox = self._mercator_bbox

        mid_dir = os.path.join(tmp_dir, self.output_dir,
                               str(self.z), str(self.x))
        mkdir_p(mid_dir)

        tile = self.tile_name()
        tile_file = os.path.join(tmp_dir, self.output_dir,
                                 tile + ".png")
        logger.debug("Generating tile %r..." % tile)

        filter_size = 10

        outfile = tile_file
        dst_bbox = bbox.bounds
        dst_x_size = 256
        dst_y_size = 256
        dst_x_res = float(dst_bbox[2] - dst_bbox[0]) / dst_x_size
        dst_y_res = float(dst_bbox[3] - dst_bbox[1]) / dst_y_size
        dst_srs = osr.SpatialReference()
        dst_srs.ImportFromEPSG(3857)

        # expand bbox & image to generate "bleed" for image filter
        mid_min_x = dst_bbox[0] - filter_size * dst_x_res
        mid_min_y = dst_bbox[1] - filter_size * dst_y_res
        mid_max_x = dst_bbox[2] + filter_size * dst_x_res
        mid_max_y = dst_bbox[3] + filter_size * dst_y_res
        filter_top_margin = filter_size
        filter_bot_margin = filter_size
        filter_lft_margin = filter_size
        filter_rgt_margin = filter_size

        # clip bounding box back to the edges of the world. GDAL can handle
        # wrapping around the world, but it doesn't give the results that
        # would be expected.
        if mid_min_x < -0.5 * mercator.MERCATOR_WORLD_SIZE:
            filter_lft_margin = 0
            mid_min_x = dst_bbox[0]
        if mid_min_y < -0.5 * mercator.MERCATOR_WORLD_SIZE:
            filter_bot_margin = 0
            mid_min_y = dst_bbox[1]
        if mid_max_x > 0.5 * mercator.MERCATOR_WORLD_SIZE:
            filter_rgt_margin = 0
            mid_max_x = dst_bbox[2]
        if mid_max_y > 0.5 * mercator.MERCATOR_WORLD_SIZE:
            filter_top_margin = 0
            mid_max_y = dst_bbox[3]

        mid_x_size = dst_x_size + filter_lft_margin + filter_rgt_margin
        mid_y_size = dst_y_size + filter_bot_margin + filter_top_margin
        mid_bbox = (mid_min_x, mid_min_y, mid_max_x, mid_max_y)

        mid_drv = gdal.GetDriverByName("MEM")
        mid_ds = mid_drv.Create('', mid_x_size, mid_y_size, 1, gdal.GDT_Float32)

        mid_gt = (mid_bbox[0], dst_x_res, 0,
                  mid_bbox[3], 0, -dst_y_res)
        mid_ds.SetGeoTransform(mid_gt)
        mid_ds.SetProjection(dst_srs.ExportToWkt())
        mid_ds.GetRasterBand(1).SetNoDataValue(mercator.FLT_NODATA)

        # figure out what the approximate scale of the output image is in
        # lat/lon coordinates. this is used to select the appropriate filter.
        ll_bbox = self._latlon_bbox
        ll_x_res = float(ll_bbox.bounds[2] - ll_bbox.bounds[0]) / dst_x_size
        ll_y_res = float(ll_bbox.bounds[3] - ll_bbox.bounds[1]) / dst_y_size

        # calculate the resolution of a pixel in real meters for both x and y.
        # this will be used to scale the gradient so that it's consistent
        # across zoom levels.
        ll_mid_x = 0.5 * (ll_bbox.bounds[2] + ll_bbox.bounds[0])
        ll_spc_x = 0.5 * (ll_bbox.bounds[2] - ll_bbox.bounds[0]) / dst_x_size
        ll_mid_y = 0.5 * (ll_bbox.bounds[3] + ll_bbox.bounds[1])
        ll_spc_y = 0.5 * (ll_bbox.bounds[3] - ll_bbox.bounds[1]) / dst_y_size
        geod = Geodesic.WGS84
        # NOTE: in defiance of predictability and regularity, the geod methods
        # take input as (lat, lon) in that order, rather than (x, y) as would
        # be sensible.
        # NOTE: at low zooms, taking the width across the tile starts to break
        # down, so we take the width across a small portion of the interior of
        # the tile instead.
        geodesic_res_x = -1.0 / \
                         geod.Inverse(ll_mid_y, ll_mid_x - ll_spc_x,
                                      ll_mid_y, ll_mid_x + ll_spc_x)['s12']
        geodesic_res_y = 1.0 / \
                         geod.Inverse(ll_mid_y - ll_spc_y, ll_mid_x,
                                      ll_mid_y + ll_spc_y, ll_mid_x)['s12']

        composite.compose(self, mid_ds, logger, min(ll_x_res, ll_y_res))

        pixels = mid_ds.GetRasterBand(1).ReadAsArray(0, 0, mid_x_size, mid_y_size)
        ygrad, xgrad = numpy.gradient(pixels, 2)
        img = numpy.dstack((geodesic_res_x * xgrad, geodesic_res_y * ygrad,
                            numpy.ones((mid_y_size, mid_x_size))))

        # first, we normalise to unit vectors. this puts each element of img
        # in the range (-1, 1). the "einsum" stuff is serious black magic, but
        # what it (should be) saying is "for each i,j in the rows and columns,
        # the output is the sum of img[i,j,k]*img[i,j,k]" - i.e: the square.
        norm = numpy.sqrt(numpy.einsum('ijk,ijk->ij', img, img))

        # the norm is now the "wrong shape" according to numpy, so we need to
        # copy the norm value out into RGB components.
        norm_copy = norm[:, :, numpy.newaxis]

        # dividing the img by norm_copy should give us RGB components with
        # values between -1 and 1, but we need values between 0 and 255 for
        # PNG channels. so we move and scale the values to fit in that range.
        scaled = (128.0 * (img / norm_copy + 1.0))

        # and finally clip it to (0, 255) just in case
        img = numpy.clip(scaled, 0.0, 255.0)

        # Create output as a 4-channel RGBA image, each (byte) channel
        # corresponds to x, y, z, h where x, y and z are the respective
        # components of the normal, and h is an index into a hypsometric tint
        # table (see HEIGHT_TABLE).
        dst_ds = mid_drv.Create('', dst_x_size, dst_y_size, 4, gdal.GDT_Byte)

        dst_gt = (dst_bbox[0], dst_x_res, 0,
                  dst_bbox[3], 0, -dst_y_res)
        dst_ds.SetGeoTransform(dst_gt)
        dst_ds.SetProjection(dst_srs.ExportToWkt())

        # apply the height mapping function to get the table index.
        func = numpy.vectorize(_height_mapping_func)
        hyps = func(pixels).astype(numpy.uint8)

        # extract the area without the "bleed" margin.
        ext = img[filter_top_margin:(filter_top_margin+dst_y_size), \
                  filter_lft_margin:(filter_lft_margin+dst_x_size)]
        dst_ds.GetRasterBand(1).WriteArray(ext[...,0].astype(numpy.uint8))
        dst_ds.GetRasterBand(2).WriteArray(ext[...,1].astype(numpy.uint8))
        dst_ds.GetRasterBand(3).WriteArray(ext[...,2].astype(numpy.uint8))

        # add hypsometric tint index as alpha channel
        dst_ds.GetRasterBand(4).WriteArray(
            hyps[filter_top_margin:(filter_top_margin+dst_y_size),
                 filter_lft_margin:(filter_lft_margin+dst_x_size)])

        png_drv = gdal.GetDriverByName("PNG")
        png_ds = png_drv.CreateCopy(tile_file, dst_ds)

        # explicitly delete the datasources. the Python-GDAL docs suggest that
        # this is a good idea not only to dispose of memory buffers but also
        # to ensure that the backing file handles are closed.
        del png_ds
        del dst_ds
        del mid_ds

        assert os.path.isfile(tile_file)

        source_names = [type(s).__name__ for s in self.sources]
        logger.info("Done generating tile %r from %s"
                    % (tile, ", ".join(source_names)))