def __init__(self, bbox=None, configuration=None, standalone=False): self.standalone = standalone self.big_bbox = bbox self.job_queue_name = 'jobs' self.mercator = GlobalMercator() self.small_bboxes = [] self.configuration = configuration
def add_meter(self, vertical_distance, horizontal_distance): mercator = GlobalMercator() copy = self.copy() lat, lon = mercator.MetersToLatLon(horizontal_distance, vertical_distance) copy.latitude += lat copy.longitude += lon return copy
def __init__(self, zoom_level=19): self.config = self._read_wms_config() self.auth = self.set_auth() self.zoom_level = zoom_level self._auth_monkey_patch(self.auth) self.mercator = GlobalMercator() from owslib.wms import WebMapService self.wms = WebMapService(url=self.config.get(section='WMS', option='Url'), version=self.config.get(section='WMS', option='Version'))
class FittingBbox: def __init__(self, zoom_level=19): self._mercator = GlobalMercator() self._zoom_level = zoom_level def get(self, bbox): t_minx, t_miny, t_maxx, t_maxy = self.bbox_to_tiles(bbox) bbox = self._bbox_from(t_minx, t_miny, t_maxx, t_maxy) return bbox def bbox_to_tiles(self, bbox): m_minx, m_miny = self._mercator.LatLonToMeters(bbox.bottom, bbox.left) m_maxx, m_maxy = self._mercator.LatLonToMeters(bbox.top, bbox.right) t_maxx, t_maxy = self._mercator.MetersToTile(m_maxx, m_maxy, self._zoom_level) t_minx, t_miny = self._mercator.MetersToTile(m_minx, m_miny, self._zoom_level) return t_minx, t_miny, t_maxx, t_maxy def generate_bbox(self, tx, ty): bottom, left, top, right = self._mercator.TileLatLonBounds( tx, ty, self._zoom_level) bbox = Bbox.from_lbrt(left, bottom, right, top) return bbox def _bbox_from(self, t_minx, t_miny, t_maxx, t_maxy): bottom, left, _, _ = self._mercator.TileLatLonBounds( t_minx, t_miny, self._zoom_level) _, _, top, right = self._mercator.TileLatLonBounds( t_maxx, t_maxy, self._zoom_level) return Bbox.from_lbrt(left, bottom, right, top)
class Manager: def __init__(self, bbox=None, configuration=None, standalone=False): self.standalone = standalone self.big_bbox = bbox self.job_queue_name = 'jobs' self.mercator = GlobalMercator() self.small_bboxes = [] self.configuration = configuration def run(self): self._generate_small_bboxes() if not self.standalone: self._enqueue_jobs(self.configuration) else: worker_functions.standalone(bboxes=self.small_bboxes, configuration=self.configuration) def _generate_small_bboxes(self): m_minx, m_miny = self.mercator.LatLonToMeters(self.big_bbox.bottom, self.big_bbox.left) rows = self._calc_rows() columns = self._calc_columns() side = int(self.configuration.JOB.bboxsize) for x in range(0, columns): for y in range(0, rows): bottom, left = self.mercator.MetersToLatLon(m_minx + (side * x), m_miny + (side * y)) top, right = self.mercator.MetersToLatLon(m_minx + (side * (x + 1)), m_miny + (side * (y + 1))) small_bbox = Bbox(left=left, bottom=bottom, right=right, top=top) self.small_bboxes.append(small_bbox) def _enqueue_jobs(self, configuration): redis_connection = Redis(host=configuration.REDIS.server, port=configuration.REDIS.port, password=configuration.REDIS.password) queue = Queue(self.job_queue_name, connection=redis_connection) for small_bbox in self.small_bboxes: queue.enqueue_call(func=worker_functions.detect, args=(small_bbox, self.configuration), timeout=self.configuration.JOB.timeout) print('Number of enqueued jobs in queue \'{0}\': {1}'.format(self.job_queue_name, len(queue))) def _calc_rows(self): _, m_miny = self.mercator.LatLonToMeters(self.big_bbox.bottom, self.big_bbox.left) _, m_maxy = self.mercator.LatLonToMeters(self.big_bbox.top, self.big_bbox.right) meter_in_y = m_maxy - m_miny return int(math.ceil(meter_in_y / int(self.configuration.JOB.bboxsize))) def _calc_columns(self): m_min_x, _ = self.mercator.LatLonToMeters(self.big_bbox.bottom, self.big_bbox.left) m_max_x, _ = self.mercator.LatLonToMeters(self.big_bbox.top, self.big_bbox.right) meter_in_x = m_max_x - m_min_x return int(math.ceil(meter_in_x / int(self.configuration.JOB.bboxsize)))
class UrlBuilder: def __init__(self, zoom_level=19): self._url_first_part = 'https://t' self._url_second_part = '.ssl.ak.tiles.virtualearth.net/tiles/a' self._url_last_part = '.jpeg?g=4401&n=z' self._zoom_level = zoom_level self._mercator = GlobalMercator() def get_urls_by_tiles(self, t_minx, t_miny, t_maxx, t_maxy): urls = [] for ty in range(t_miny, t_maxy + 1): for tx in range(t_minx, t_maxx + 1): quad_tree = self._mercator.QuadTree(tx, ty, self._zoom_level) url = self._build_url(quad_tree) urls.append(url) return urls def _build_url(self, quadtree): server = random.randint(0, 7) return self._url_first_part + str( server) + self._url_second_part + str( quadtree) + self._url_last_part
def __init__(self, zoom_level=19): self._mercator = GlobalMercator() self._zoom_level = zoom_level
class OtherApi: def __init__(self, zoom_level=19): self._mercator = GlobalMercator() self._zoom_level = zoom_level self.tile = None def get_image(self, bbox): t_minx, t_miny, t_maxx, t_maxy = self._bbox_to_tile_indexes(bbox) images = self._download_images(t_minx, t_miny, t_maxx, t_maxy) image_matrix = self._to_image_matrix(images, t_minx, t_miny, t_maxx, t_maxy) image = self._to_image(image_matrix) big_bbox = self._generate_bbox(t_minx, t_miny, t_maxx, t_maxy) self.tile = Tile(image, big_bbox) return self._crop(self.tile, bbox) @staticmethod def _to_image_matrix(images, t_minx, t_miny, t_maxx, t_maxy): image_matrix = [] row = 0 url_number = 0 for ty in range(t_miny, t_maxy + 1): image_matrix.append([]) for tx in range(t_minx, t_maxx + 1): image = images[url_number] image_matrix[row].append(image) url_number += 1 row += 1 return image_matrix def _download_images(self, t_minx, t_miny, t_maxx, t_maxy): url_builder = UrlBuilder(self._zoom_level) urls = url_builder.get_urls_by_tiles(t_minx, t_miny, t_maxx, t_maxy) loader = MultiLoader(urls) loader.download() return loader.results @staticmethod def _to_image(image_matrix): num_rows = len(image_matrix) num_cols = len(image_matrix[0]) width, height = image_matrix[0][0].size result = Image.new("RGB", (num_cols * width, num_rows * height)) for y in range(0, num_rows): for x in range(0, num_cols): result.paste(image_matrix[y][x], (x * width, (num_rows - 1 - y) * height)) return result def _bbox_to_tile_indexes(self, bbox): m_minx, m_miny = self._mercator.LatLonToMeters(bbox.bottom, bbox.left) m_maxx, m_maxy = self._mercator.LatLonToMeters(bbox.top, bbox.right) t_maxx, t_maxy = self._mercator.MetersToTile(m_maxx, m_maxy, self._zoom_level) t_minx, t_miny = self._mercator.MetersToTile(m_minx, m_miny, self._zoom_level) return t_minx, t_miny, t_maxx, t_maxy def _generate_bbox(self, t_minx, t_miny, t_maxx, t_maxy): bottom, left, _, _ = self._mercator.TileLatLonBounds(t_minx, t_miny, self._zoom_level) _, _, top, right = self._mercator.TileLatLonBounds(t_maxx, t_maxy, self._zoom_level) return Bbox(left=left, bottom=bottom, right=right, top=top) @staticmethod def _crop(tile, bbox): left, bottom = tile.get_pixel(bbox.node_left_down()) right, top = tile.get_pixel(bbox.node_right_up()) box = (left, top, right, bottom) cropped_image = tile.image.crop(box) image = Image.frombytes(mode='RGB', data=cropped_image.tobytes(), size=cropped_image.size) return image
def _calculate_max_distance(zoom_level, square_image_length): global_mercator = GlobalMercator() resolution = global_mercator.Resolution(zoom_level) return resolution * (square_image_length / 2)
def _calculate_step_distance(self, zoom_level): global_mercator = GlobalMercator() resolution = global_mercator.Resolution(zoom_level) return resolution * (self._square_image_length / 1.5)
class WmsApi: def __init__(self, zoom_level=19): self.config = self._read_wms_config() self.auth = self.set_auth() self.zoom_level = zoom_level self._auth_monkey_patch(self.auth) self.mercator = GlobalMercator() from owslib.wms import WebMapService self.wms = WebMapService(url=self.config.get(section='WMS', option='Url'), version=self.config.get(section='WMS', option='Version')) def set_auth(self): user = self.config.get(section='CREDENTIALS', option='NtlmUser', fallback=None) password = self.config.get(section='CREDENTIALS', option='NtlmPassword', fallback=None) return HttpNtlmAuth( user, password) if user is not None and password is not None else None def _read_wms_config(self): current_directory = os.path.dirname(os.path.abspath(__file__)) config_file = os.path.join(current_directory, 'wms.ini') config = configparser.ConfigParser() if not os.path.isfile(config_file): raise Exception("The WMS config file does not exist! " + config_file) config.read(config_file) self.check_wms_config_fields(config) return config @staticmethod def _auth_monkey_patch(auth): AuthMonkeyPatch(auth) def get_image(self, bbox): bbox_ = self._box(bbox) bbox_ = self.mercator.LatLonToMeters( bbox_[3], bbox_[0]) + self.mercator.LatLonToMeters( bbox_[1], bbox_[2]) size = self._calculate_image_size(bbox, self.zoom_level) image = self._get( layers=[self.config.get(section='WMS', option='Layer')], srs=self.config.get(section='WMS', option='Srs'), bbox=bbox_, size=size, format='image/jpeg', ) return image def get_image_size(self, bbox): return self._calculate_image_size(bbox, self.zoom_level) @staticmethod def _calculate_image_size(bbox, zoom_level): meters_per_pixel = geo_helper.meters_per_pixel(zoom_level, bbox.bottom) width_meter = bbox.node_left_down().get_distance_in_meter( bbox.node_right_down()) height_meter = bbox.node_left_down().get_distance_in_meter( bbox.node_left_up()) height = int(height_meter / meters_per_pixel) width = int(width_meter / meters_per_pixel) return width, height def _get(self, **kwargs): img = self.wms.getmap(**kwargs) return Image.open(BytesIO(img.read())) @staticmethod def _box(bbox): node_left_down = bbox.node_left_down() node_right_up = bbox.node_right_up() return node_left_down.longitude, node_left_down.latitude, node_right_up.longitude, node_right_up.latitude @staticmethod def check_wms_config_fields(config): if not config.has_section('WMS'): raise Exception("Section 'WMS' is not in WMS config file!") if not config.has_option('WMS', 'Url'): raise Exception("'Url' is not in 'WMS' section!") if not config.has_option('WMS', 'Srs'): raise Exception("'Srs' is not in 'WMS' section!") if not config.has_option('WMS', 'Version'): raise Exception("'Version' is not in 'WMS' section!") if not config.has_option('WMS', 'Layer'): raise Exception("'Layer' is not in 'WMS' section!")
def __init__(self, bbox, job_queue_name, search=None): self.big_bbox = bbox self.job_queue_name = job_queue_name self.mercator = GlobalMercator() self.small_bboxes = [] self.search = self._search(search)
class Manager(object): small_bbox_side_length = 2000.0 timeout = 5400 def __init__(self, bbox, job_queue_name, search=None): self.big_bbox = bbox self.job_queue_name = job_queue_name self.mercator = GlobalMercator() self.small_bboxes = [] self.search = self._search(search) @classmethod def from_big_bbox(cls, big_bbox, redis, job_queue_name, search=None): manager = cls(big_bbox, job_queue_name, cls._search(search)) manager._generate_small_bboxes() manager._enqueue_jobs(redis) return manager def _generate_small_bboxes(self): m_minx, m_miny = self.mercator.LatLonToMeters(self.big_bbox.bottom, self.big_bbox.left) rows = self._calc_rows() columns = self._calc_columns() side = Manager.small_bbox_side_length for x in range(0, columns): for y in range(0, rows): bottom, left = self.mercator.MetersToLatLon( m_minx + (side * x), m_miny + (side * y)) top, right = self.mercator.MetersToLatLon( m_minx + (side * (x + 1)), m_miny + (side * (y + 1))) small_bbox = Bbox.from_lbrt(left, bottom, right, top) self.small_bboxes.append(small_bbox) def _enqueue_jobs(self, redis): redis_connection = Redis(redis[0], redis[1], password=redis[2]) queue = Queue(self.job_queue_name, connection=redis_connection) for small_bbox in self.small_bboxes: queue.enqueue_call(func=detect, args=(small_bbox, redis, self.search), timeout=Manager.timeout) print('Number of enqueued jobs in queue \'{0}\': {1}'.format( self.job_queue_name, len(queue))) def _calc_rows(self): _, m_miny = self.mercator.LatLonToMeters(self.big_bbox.bottom, self.big_bbox.left) _, m_maxy = self.mercator.LatLonToMeters(self.big_bbox.top, self.big_bbox.right) meter_in_y = m_maxy - m_miny return int(math.ceil(meter_in_y / Manager.small_bbox_side_length)) def _calc_columns(self): m_min_x, _ = self.mercator.LatLonToMeters(self.big_bbox.bottom, self.big_bbox.left) m_max_x, _ = self.mercator.LatLonToMeters(self.big_bbox.top, self.big_bbox.right) meter_in_x = m_max_x - m_min_x return int(math.ceil(meter_in_x / Manager.small_bbox_side_length)) @staticmethod def _search(search): return Search() if search is None else search
def __init__(self, zoom_level=19): self._url_first_part = 'https://t' self._url_second_part = '.ssl.ak.tiles.virtualearth.net/tiles/a' self._url_last_part = '.jpeg?g=4401&n=z' self._zoom_level = zoom_level self._mercator = GlobalMercator()