正在显示
46 个修改的文件
包含
1774 行增加
和
208 行删除
... | ... | @@ -265,9 +265,10 @@ pkgs.extend(list(glob.glob('%s/modules/*/*/models' % (current_dir)))) |
265 | 265 | for pkg in pkgs : |
266 | 266 | pkg = os.path.normpath(pkg) |
267 | 267 | node_list = pkg.split(os.path.sep) |
268 | - pkg_name = ".".join(node_list[node_list.index("app"):]) | |
268 | + pkg_name = "app.{}".format(".".join(node_list[node_list.index("modules"):])) | |
269 | 269 | try: |
270 | - __import__(pkg_name) | |
270 | + if pkg_name.__contains__("models"): | |
271 | + __import__(pkg_name) | |
271 | 272 | except Exception as e: |
272 | 273 | print(traceback.format_exc()) |
273 | 274 | pass |
\ No newline at end of file | ... | ... |
... | ... | @@ -7,9 +7,10 @@ from flasgger import swag_from |
7 | 7 | from flask import Blueprint |
8 | 8 | from app.util import BlueprintApi |
9 | 9 | from . import service_register |
10 | -from . import service_type | |
10 | +from . import service_exist_type | |
11 | 11 | from . import service_list |
12 | 12 | from . import service_delete |
13 | +from . import service_state | |
13 | 14 | import os |
14 | 15 | from flask import send_from_directory |
15 | 16 | |
... | ... | @@ -17,6 +18,8 @@ from flask import send_from_directory |
17 | 18 | class DataManager(BlueprintApi): |
18 | 19 | |
19 | 20 | bp = Blueprint("Service", __name__, url_prefix="/API/Service") |
21 | + service_type = [] | |
22 | + | |
20 | 23 | |
21 | 24 | @staticmethod |
22 | 25 | @bp.route('/Register', methods=['POST']) |
... | ... | @@ -29,12 +32,21 @@ class DataManager(BlueprintApi): |
29 | 32 | |
30 | 33 | @staticmethod |
31 | 34 | @bp.route('/Type', methods=['GET']) |
32 | - @swag_from(service_type.Api.api_doc) | |
35 | + @swag_from(service_exist_type.Api.api_doc) | |
33 | 36 | def api_service_type(): |
34 | 37 | """ |
35 | 38 | 可用服务类型 |
36 | 39 | """ |
37 | - return service_type.Api().result | |
40 | + return service_exist_type.Api().result | |
41 | + | |
42 | + @staticmethod | |
43 | + @bp.route('/State', methods=['GET']) | |
44 | + @swag_from(service_state.Api.api_doc) | |
45 | + def api_service_state(): | |
46 | + """ | |
47 | + 修改服务状态 | |
48 | + """ | |
49 | + return service_state.Api().result | |
38 | 50 | |
39 | 51 | @staticmethod |
40 | 52 | @bp.route('/List', methods=['POST']) | ... | ... |
... | ... | @@ -19,7 +19,7 @@ from . import catalog_edit, catalog_tree, catalog_delete, catalog_create, catalo |
19 | 19 | class DataManager(BlueprintApi): |
20 | 20 | |
21 | 21 | bp = Blueprint("ServiceCatalog", __name__, url_prefix="/API/Service/Catalog") |
22 | - | |
22 | + service_type = [] | |
23 | 23 | |
24 | 24 | @staticmethod |
25 | 25 | @bp.route('/Create', methods=['POST']) | ... | ... |
... | ... | @@ -17,7 +17,7 @@ from . import feature_edit |
17 | 17 | class DataManager(BlueprintApi): |
18 | 18 | |
19 | 19 | bp = Blueprint("FeatureService", __name__, url_prefix="/API/FeatureService") |
20 | - service_type = ["要素服务"] | |
20 | + service_type = [] | |
21 | 21 | @staticmethod |
22 | 22 | @bp.route('/Query', methods=['POST']) |
23 | 23 | @swag_from(feature_query.Api.api_doc) | ... | ... |
... | ... | @@ -7,22 +7,23 @@ |
7 | 7 | from flasgger import swag_from |
8 | 8 | from flask import Blueprint |
9 | 9 | from app.util import BlueprintApi |
10 | -from . import image_register | |
11 | 10 | from . import image_service_register |
12 | 11 | from . import image_server_list |
13 | 12 | from . import data_list |
14 | 13 | from . import capabilities |
15 | -from . import image_list | |
16 | -from . import image_tile | |
17 | -from . import image_wms | |
18 | -from . import image_overview | |
14 | +from . import image_tile,image_wms | |
19 | 15 | from . import image_service_list |
16 | +from . import image_tile_mask | |
17 | + | |
18 | + | |
19 | +from . import image_register,image_list,image_info,image_edit,image_overview | |
20 | +from . import image_tag_create,image_tag_delete,image_tag_list | |
20 | 21 | |
21 | 22 | |
22 | 23 | class DataManager(BlueprintApi): |
23 | 24 | |
24 | 25 | bp = Blueprint("Image", __name__, url_prefix="/API/Service/Image") |
25 | - service_type = ["影像WMS服务","影像WMTS服务"] | |
26 | + service_type = ["ImageWMS","ImageWMTS"] | |
26 | 27 | |
27 | 28 | @staticmethod |
28 | 29 | @bp.route('/Register', methods=['POST']) |
... | ... | @@ -33,6 +34,24 @@ class DataManager(BlueprintApi): |
33 | 34 | """ |
34 | 35 | return image_register.Api().result |
35 | 36 | |
37 | + @staticmethod | |
38 | + @bp.route('/Edit', methods=['POST']) | |
39 | + @swag_from(image_edit.Api.api_doc) | |
40 | + def api_image_edit(): | |
41 | + """ | |
42 | + 影像Info | |
43 | + """ | |
44 | + return image_edit.Api().result | |
45 | + | |
46 | + @staticmethod | |
47 | + @bp.route('/Info', methods=['POST']) | |
48 | + @swag_from(image_info.Api.api_doc) | |
49 | + def api_image_info(): | |
50 | + """ | |
51 | + 影像Info | |
52 | + """ | |
53 | + return image_info.Api().result | |
54 | + | |
36 | 55 | |
37 | 56 | @staticmethod |
38 | 57 | @bp.route('/Overview', methods=['POST']) |
... | ... | @@ -43,6 +62,35 @@ class DataManager(BlueprintApi): |
43 | 62 | """ |
44 | 63 | return image_overview.Api().result |
45 | 64 | |
65 | + | |
66 | + @staticmethod | |
67 | + @bp.route('/TagCreate', methods=['POST']) | |
68 | + @swag_from(image_tag_create.Api.api_doc) | |
69 | + def api_image_tag_create(): | |
70 | + """ | |
71 | + Tag创建 | |
72 | + """ | |
73 | + return image_tag_create.Api().result | |
74 | + | |
75 | + @staticmethod | |
76 | + @bp.route('/TagDelete', methods=['POST']) | |
77 | + @swag_from(image_tag_delete.Api.api_doc) | |
78 | + def api_image_tag_delete(): | |
79 | + """ | |
80 | + Tag删除 | |
81 | + """ | |
82 | + return image_tag_delete.Api().result | |
83 | + | |
84 | + @staticmethod | |
85 | + @bp.route('/TagList', methods=['POST']) | |
86 | + @swag_from(image_tag_list.Api.api_doc) | |
87 | + def api_image_tag_list(): | |
88 | + """ | |
89 | + TagList | |
90 | + """ | |
91 | + return image_tag_list.Api().result | |
92 | + | |
93 | + | |
46 | 94 | @staticmethod |
47 | 95 | @bp.route('/ServiceRegister', methods=['POST']) |
48 | 96 | @swag_from(image_service_register.Api.api_doc) |
... | ... | @@ -117,6 +165,24 @@ class DataManager(BlueprintApi): |
117 | 165 | """ |
118 | 166 | return image_tile.Api("1",1,1,1).result |
119 | 167 | |
168 | + # @staticmethod | |
169 | + # @bp.route('/TileMask/<guid>/<l>/<y>/<z>', methods=['GET']) | |
170 | + # @swag_from(image_tile_mask.Api.api_doc) | |
171 | + # def api_image_tile_mask(guid,l,y,z): | |
172 | + # """ | |
173 | + # 切片服务 | |
174 | + # """ | |
175 | + # return image_tile_mask.Api(guid,l,y,z).result | |
176 | + # | |
177 | + # @staticmethod | |
178 | + # @bp.route('/TileMask', methods=['GET','POST']) | |
179 | + # @swag_from(image_tile_mask.Api.api_doc) | |
180 | + # def api_image_tile_mask_kv(): | |
181 | + # """ | |
182 | + # 切片服务 | |
183 | + # """ | |
184 | + # return image_tile_mask.Api("1",1,1,1).result | |
185 | + | |
120 | 186 | |
121 | 187 | |
122 | 188 | @staticmethod | ... | ... |
... | ... | @@ -11,6 +11,9 @@ from app.util.component.FileProcess import FileProcess |
11 | 11 | import datetime |
12 | 12 | from app.modules.service.image.util.ThriftConnect import ThriftConnect |
13 | 13 | import os |
14 | +from app.models import db | |
15 | +from app.modules.service.image.models import Image | |
16 | + | |
14 | 17 | class Api(ApiTemplate): |
15 | 18 | |
16 | 19 | api_name = "影像数据列表" |
... | ... | @@ -38,11 +41,20 @@ class Api(ApiTemplate): |
38 | 41 | for f in os.listdir(base_path): |
39 | 42 | |
40 | 43 | file_path = os.path.normpath(os.path.join(base_path, f)) |
41 | - file_size = FileProcess.get_file_size(file_path) | |
44 | + file_size, real_size = FileProcess.get_file_size(file_path) | |
42 | 45 | |
43 | 46 | fctime = datetime.datetime.fromtimestamp(os.path.getctime(file_path)).strftime('%Y-%m-%d %H:%M:%S') |
44 | 47 | |
45 | - file_info = {"name": f, "path": file_path, "size": file_size, "create_time": fctime} | |
48 | + file_info = {"name": f, "path": file_path, "size": file_size, "create_time": fctime,"real_size": real_size} | |
49 | + | |
50 | + if file_path.lower().endswith("tiff") or file_path.lower().endswith("tif") or file_path.lower().endswith("img"): | |
51 | + | |
52 | + exist_image: Image = Image.query.filter_by(path=os.path.normpath(file_info.get("path")), | |
53 | + size=file_info.get("size")).one_or_none() | |
54 | + file_info["exist"] = False | |
55 | + if exist_image: | |
56 | + if exist_image.server.__contains__(data_server): | |
57 | + file_info["exist"] = True | |
46 | 58 | |
47 | 59 | if file_path.lower().endswith("tiff") or file_path.lower().endswith("tif"): |
48 | 60 | file_info["type"] = "tif" |
... | ... | @@ -61,6 +73,17 @@ class Api(ApiTemplate): |
61 | 73 | thrift_connect = ThriftConnect(data_server) |
62 | 74 | info= json.loads(thrift_connect.client.getImageList(path)) |
63 | 75 | thrift_connect.close() |
76 | + | |
77 | + for inf in info: | |
78 | + if inf["path"].lower().endswith("tiff") or inf["path"].lower().endswith("tif") or inf["path"].lower().endswith("img"): | |
79 | + dd = os.path.normpath(inf.get("path")) | |
80 | + exist_image = Image.query.filter_by(path=os.path.normpath(inf.get("path")), | |
81 | + size=inf.get("real_size")).one_or_none() | |
82 | + inf["exist"] = False | |
83 | + if exist_image: | |
84 | + if exist_image.server.__contains__(data_server): | |
85 | + inf["exist"] = True | |
86 | + | |
64 | 87 | res["data"] = info |
65 | 88 | |
66 | 89 | res["result"] = True | ... | ... |
... | ... | @@ -41,6 +41,12 @@ class Api(ApiTemplate): |
41 | 41 | {"name": "alias", |
42 | 42 | "in": "formData", |
43 | 43 | "type": "string"}, |
44 | + {"name": "ym", | |
45 | + "in": "formData", | |
46 | + "type": "string","description":"成像时间字符串"}, | |
47 | + {"name": "region", | |
48 | + "in": "formData", | |
49 | + "type": "string", "description": "所属区域"}, | |
44 | 50 | ], |
45 | 51 | "responses": { |
46 | 52 | 200: { | ... | ... |
app/modules/service/image/image_info.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: 4N | |
3 | +#createtime: 2021/7/19 | |
4 | +#email: nheweijun@sina.com | |
5 | + | |
6 | + | |
7 | +from app.util.component.ApiTemplate import ApiTemplate | |
8 | +from app.util.component.ModelVisitor import ModelVisitor | |
9 | + | |
10 | +from app.modules.service.image.models import Image,ImageTag | |
11 | +from sqlalchemy import or_,and_ | |
12 | +class Api(ApiTemplate): | |
13 | + | |
14 | + api_name = "影像数据Info" | |
15 | + | |
16 | + def process(self): | |
17 | + | |
18 | + # 返回结果 | |
19 | + res = {} | |
20 | + try: | |
21 | + | |
22 | + guid = self.para.get("guid") | |
23 | + | |
24 | + image = Image.query.filter_by(guid=guid).one_or_none() | |
25 | + if not image: | |
26 | + raise Exception("数据不存在!") | |
27 | + tags:ImageTag = image.image_tags.all() | |
28 | + tag_names = [tag.name for tag in tags] | |
29 | + | |
30 | + res["data"] = ModelVisitor.object_to_json(image) | |
31 | + res["data"]["tag"] = ",".join(tag_names) | |
32 | + res["result"] = True | |
33 | + except Exception as e: | |
34 | + raise e | |
35 | + | |
36 | + return res | |
37 | + | |
38 | + | |
39 | + api_doc = { | |
40 | + "tags": ["影像接口"], | |
41 | + "parameters": [ | |
42 | + {"name": "guid", | |
43 | + "in": "formData", | |
44 | + "type": "string"}, | |
45 | + ], | |
46 | + "responses": { | |
47 | + 200: { | |
48 | + "schema": { | |
49 | + "properties": { | |
50 | + } | |
51 | + } | |
52 | + } | |
53 | + } | |
54 | + } | |
55 | + | |
56 | + | ... | ... |
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | from app.util.component.ApiTemplate import ApiTemplate |
8 | 8 | from app.util.component.ModelVisitor import ModelVisitor |
9 | 9 | |
10 | -from app.modules.service.image.models import Image | |
10 | +from app.modules.service.image.models import Image,ImageTag | |
11 | 11 | from sqlalchemy import or_,and_ |
12 | 12 | class Api(ApiTemplate): |
13 | 13 | |
... | ... | @@ -23,6 +23,8 @@ class Api(ApiTemplate): |
23 | 23 | |
24 | 24 | alias = self.para.get("alias") |
25 | 25 | name = self.para.get("name") |
26 | + tag_guid = self.para.get("tag_guid") | |
27 | + | |
26 | 28 | images = Image.query |
27 | 29 | |
28 | 30 | # 并集 |
... | ... | @@ -33,6 +35,11 @@ class Api(ApiTemplate): |
33 | 35 | images = images.filter(Image.alias.like("%" + alias + "%")) |
34 | 36 | if name: |
35 | 37 | images = images.filter(Image.name.like("%" + name + "%")) |
38 | + if tag_guid: | |
39 | + tag:ImageTag = ImageTag.query.filter_by(guid=tag_guid).one_or_none() | |
40 | + images_guid = [img.guid for img in tag.images.all()] | |
41 | + images = images.filter(Image.guid.in_(images_guid)) | |
42 | + | |
36 | 43 | |
37 | 44 | images = images.limit(page_size).offset(page_index).all() |
38 | 45 | |
... | ... | @@ -61,6 +68,9 @@ class Api(ApiTemplate): |
61 | 68 | {"name": "name", |
62 | 69 | "in": "formData", |
63 | 70 | "type": "string"}, |
71 | + {"name": "tag_guid", | |
72 | + "in": "formData", | |
73 | + "type": "string"}, | |
64 | 74 | ], |
65 | 75 | "responses": { |
66 | 76 | 200: { | ... | ... |
... | ... | @@ -47,11 +47,18 @@ class Api(ApiTemplate): |
47 | 47 | image = Image.query.filter_by(guid=guid).one_or_none() |
48 | 48 | # 该影像的服务器,随机选取一个 |
49 | 49 | image_servers = image.server.split(",") |
50 | - indx = int(random.random() * len(image_servers)) | |
51 | - image_server = image_servers[indx] | |
50 | + image_servers = [ser for ser in image_servers if zoo.exists("/rpc/{}".format(ser)) or ser.__eq__("本地服务器") ] | |
51 | + if len(image_servers) > 0: | |
52 | + indx = int(random.random() * len(image_servers)) | |
53 | + image_server = image_servers[indx] | |
54 | + else: | |
55 | + image_server = "None" | |
56 | + | |
52 | 57 | wms_api = WMSApi() |
53 | 58 | |
54 | - bands = [1,2,3] if image.band_count>=3 else [1,1,1] | |
59 | + bands = json.loads(image.band_view) | |
60 | + | |
61 | + # bands = [1,2,3] if image.band_count>=3 else [1,1,1] | |
55 | 62 | |
56 | 63 | #计算查询范围,保持正常比例 |
57 | 64 | query_extent = json.loads(image.extent) |
... | ... | @@ -63,7 +70,7 @@ class Api(ApiTemplate): |
63 | 70 | query_extent = [query_extent[0] - offset, query_extent[1], query_extent[2] + offset, query_extent[3]] |
64 | 71 | |
65 | 72 | |
66 | - pixel_array_t = wms_api.get_data(zoo, image_server, image, query_extent, bands, 256, 256) | |
73 | + pixel_array_t = wms_api.get_data(image_server, image, query_extent, bands, 256, 256) | |
67 | 74 | |
68 | 75 | |
69 | 76 | pixel_array = numpy.zeros((256, 256, 3), dtype=int) | ... | ... |
... | ... | @@ -14,7 +14,9 @@ import datetime |
14 | 14 | from app.models import db |
15 | 15 | import uuid |
16 | 16 | import os |
17 | +from .models import ImageTag | |
17 | 18 | import math |
19 | + | |
18 | 20 | class Api(ApiTemplate): |
19 | 21 | |
20 | 22 | api_name = "注册影像数据" |
... | ... | @@ -28,6 +30,12 @@ class Api(ApiTemplate): |
28 | 30 | try: |
29 | 31 | data_server = self.para.get("data_server") |
30 | 32 | paths = json.loads(self.para.get("paths")) |
33 | + tag_guids = self.para.get("tag_guids") | |
34 | + if tag_guids: | |
35 | + tags = db.session.query(ImageTag).filter(ImageTag.guid.in_(tag_guids.split(","))).all() | |
36 | + else: | |
37 | + tags = [] | |
38 | + | |
31 | 39 | |
32 | 40 | #注册某影像 |
33 | 41 | infos = [] |
... | ... | @@ -43,7 +51,7 @@ class Api(ApiTemplate): |
43 | 51 | origin = osr.SpatialReference() |
44 | 52 | origin.ImportFromWkt(image.GetProjection()) |
45 | 53 | |
46 | - authority_code = origin.GetAuthorityCode() | |
54 | + authority_code = origin.GetAuthorityCode(None) | |
47 | 55 | band_count = image.RasterCount |
48 | 56 | band: Band = image.GetRasterBand(1) |
49 | 57 | count = band.GetOverviewCount() |
... | ... | @@ -63,6 +71,7 @@ class Api(ApiTemplate): |
63 | 71 | # geo_origin_extent = [geo_left_top[1], geo_right_buttom[0], geo_right_buttom[1], geo_left_top[0]] |
64 | 72 | |
65 | 73 | info = {"band_count": band_count, |
74 | + "band_view":"[1,2,3]" if band_count>=3 else "[1,1,1]", | |
66 | 75 | "overview_count": count, |
67 | 76 | "path":image_info["path"], |
68 | 77 | "xy_size": [image.RasterXSize, image.RasterYSize], |
... | ... | @@ -108,17 +117,17 @@ class Api(ApiTemplate): |
108 | 117 | if exist_image.server.__contains__(data_server): |
109 | 118 | pass |
110 | 119 | else: |
111 | - exist_image.update({"server":"{},".format(data_server)}) | |
120 | + exist_image.update({"server":"{},{}".format(exist_image.server,data_server)}) | |
112 | 121 | else: |
113 | - image = Image(guid= uuid.uuid1().__str__(), | |
122 | + img:Image = Image(guid= uuid.uuid1().__str__(), | |
114 | 123 | overview_count=info.get("overview_count"), |
115 | 124 | raster_x_size=info["xy_size"][0], |
116 | 125 | raster_y_size=info["xy_size"][1], |
117 | 126 | cell_x_size = info.get("cell_x_size"), |
118 | 127 | cell_y_size = abs(info.get("cell_y_size")), |
119 | 128 | name=os.path.basename(info.get("path")), |
129 | + alias = os.path.basename(info.get("path")), | |
120 | 130 | extent=json.dumps(info["origin_extent"]), |
121 | - # geo_origin_extent = json.dumps(info["geo_origin_extent"]), | |
122 | 131 | null_value=info.get("null_value"), |
123 | 132 | server=data_server, |
124 | 133 | path = os.path.normpath(info.get("path")), |
... | ... | @@ -129,12 +138,10 @@ class Api(ApiTemplate): |
129 | 138 | band_count=info.get("band_count"), |
130 | 139 | create_time=this_time |
131 | 140 | ) |
132 | - db.session.add(image) | |
141 | + for tag in tags: | |
142 | + img.image_tags.append(tag) | |
143 | + db.session.add(img) | |
133 | 144 | db.session.commit() |
134 | - # res["data"] = guid | |
135 | - | |
136 | - | |
137 | - | |
138 | 145 | res["result"] = True |
139 | 146 | |
140 | 147 | except Exception as e: |
... | ... | @@ -181,7 +188,11 @@ class Api(ApiTemplate): |
181 | 188 | {"name": "paths", |
182 | 189 | "in": "formData", |
183 | 190 | "type": "string", |
184 | - "description": "paths"} | |
191 | + "description": "paths"}, | |
192 | + {"name": "tags", | |
193 | + "in": "formData", | |
194 | + "type": "string", | |
195 | + "description": "tags以,相隔"} | |
185 | 196 | ], |
186 | 197 | "responses": { |
187 | 198 | 200: { | ... | ... |
... | ... | @@ -139,7 +139,7 @@ class Api(ApiTemplate): |
139 | 139 | {"name": "type", |
140 | 140 | "in": "formData", |
141 | 141 | "type": "string", |
142 | - "enum": ["WMS", "WMTS", "影像WMS", "影像WMTS"], | |
142 | + "enum": ["WMS/WFS","WMTS","MTS","ImageWMS","ImageWMTS"], | |
143 | 143 | "required": "true", |
144 | 144 | "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, |
145 | 145 | {"name": "catalog_guid", | ... | ... |
... | ... | @@ -19,21 +19,18 @@ import cv2 |
19 | 19 | from app.modules.service.image.models import ImageService,Image |
20 | 20 | from app.models import db,TileScheme |
21 | 21 | from app.util.component.ApiTemplate import ApiTemplate |
22 | -import uuid | |
23 | 22 | from app.util.component.SliceScheme import SliceScheme |
24 | -from app.util.component.FileProcess import FileProcess | |
25 | 23 | from app.util.component.ParameterUtil import ParameterUtil |
26 | -from app.util.component.GeometryAdapter import GeometryAdapter | |
27 | -import os | |
28 | 24 | import json |
29 | 25 | from kazoo.client import KazooClient |
30 | - | |
31 | 26 | from threading import Thread |
32 | - | |
33 | -from app.modules.service.image.util.ThriftConnect import ThriftConnect | |
34 | -from flask import current_app | |
27 | +from app.modules.service.image.util.ThriftConnect import ThriftConnect,ThriftPool | |
35 | 28 | import gzip |
36 | 29 | import random |
30 | +import copy | |
31 | + | |
32 | + | |
33 | + | |
37 | 34 | class Api(ApiTemplate): |
38 | 35 | |
39 | 36 | api_name = "切片" |
... | ... | @@ -46,7 +43,7 @@ class Api(ApiTemplate): |
46 | 43 | self.col = col |
47 | 44 | |
48 | 45 | def process(self): |
49 | - from app import GLOBAL_DIC | |
46 | + | |
50 | 47 | result = {} |
51 | 48 | parameter: dict = self.para |
52 | 49 | |
... | ... | @@ -54,33 +51,13 @@ class Api(ApiTemplate): |
54 | 51 | if parameter.get("guid"): |
55 | 52 | self.guid = parameter.get("guid") |
56 | 53 | |
57 | - #缓存服务信息 | |
58 | - image_service_info = GLOBAL_DIC.get(self.guid) | |
59 | - if image_service_info is None: | |
60 | - image_service:ImageService = ImageService.query.filter_by(guid = self.guid).one_or_none() | |
61 | - images = image_service.images.all() | |
62 | - scheme:TileScheme = TileScheme.query.filter_by(guid=image_service.scheme_guid).one_or_none() | |
63 | - GLOBAL_DIC[self.guid] = {"service":image_service,"images":images,"scheme":json.loads(scheme.parameter)} | |
64 | - image_service_info = GLOBAL_DIC[self.guid] | |
65 | - else: | |
66 | - image_service_info = GLOBAL_DIC[self.guid] | |
67 | - | |
68 | - zoo = GLOBAL_DIC.get("zookeeper") | |
69 | - if zoo is None: | |
70 | - zoo :KazooClient = KazooClient(hosts=configure.zookeeper, timeout=100) | |
71 | - zoo.start() | |
72 | - GLOBAL_DIC["zookeeper"] = zoo | |
73 | - else : | |
74 | - if not zoo.connected: | |
75 | - zoo.start() | |
76 | - | |
77 | - bands = [1, 2, 3] | |
54 | + image_service_info, zoo, servers = self.cache_data() | |
78 | 55 | |
56 | + # bands = [1, 2, 3] | |
79 | 57 | |
80 | 58 | # 转换参数 |
81 | 59 | parameter = ParameterUtil.to_lower(parameter) |
82 | 60 | |
83 | - | |
84 | 61 | if parameter.get("tilematrix"): |
85 | 62 | if parameter.get("tilematrix").__contains__(":"): |
86 | 63 | self.level = int(parameter.get("tilematrix").split(":")[-1]) |
... | ... | @@ -96,7 +73,6 @@ class Api(ApiTemplate): |
96 | 73 | slice_para = image_service_info["scheme"] |
97 | 74 | extent = SliceScheme.get_polygon(slice_para, self.level, self.row, self.col) |
98 | 75 | |
99 | - | |
100 | 76 | height, width = 256,256 |
101 | 77 | |
102 | 78 | # 多线程获取分布式数据 |
... | ... | @@ -106,20 +82,25 @@ class Api(ApiTemplate): |
106 | 82 | if len(intersect_image) > 1: |
107 | 83 | |
108 | 84 | # 结果矩阵 |
109 | - empty_list = [numpy.zeros((height, width), dtype=int) + 65536, | |
110 | - numpy.zeros((height, width), dtype=int) + 65536, | |
111 | - numpy.zeros((height, width), dtype=int) + 65536] | |
85 | + pixel_array = numpy.zeros((height, width, 3), dtype=int) + 65536 | |
112 | 86 | |
113 | - pixel_array = numpy.zeros((height, width, 3), dtype=int) | |
114 | 87 | thread_list = [] |
115 | 88 | |
116 | 89 | for image in intersect_image: |
90 | + | |
117 | 91 | # 该影像的服务器,随机选取一个 |
118 | 92 | image_servers = image.server.split(",") |
119 | - indx = int(random.random() * len(image_servers)) | |
120 | - image_server = image_servers[indx] | |
93 | + image_servers = [ser for ser in image_servers if ser in servers] | |
94 | + if len(image_servers)>0: | |
95 | + indx = int(random.random() * len(image_servers)) | |
96 | + image_server = image_servers[indx] | |
97 | + else: | |
98 | + image_server = "None" | |
99 | + | |
100 | + bands = json.loads(image.band_view) | |
101 | + | |
121 | 102 | thread: MyThread = MyThread(self.get_data, |
122 | - args=(zoo, image_server, image, extent, bands, height, width)) | |
103 | + args=(image_server, image, extent, bands, height, width)) | |
123 | 104 | thread.start() |
124 | 105 | thread_list.append(thread) |
125 | 106 | |
... | ... | @@ -128,51 +109,106 @@ class Api(ApiTemplate): |
128 | 109 | data = thread.get_result() |
129 | 110 | |
130 | 111 | # 掩膜在中央接口生成,合图 |
131 | - mask = numpy.zeros((height, width), dtype=int) | |
132 | - mask2 = numpy.zeros((height, width), dtype=int) | |
133 | - jizhun = data[:, :, 0] | |
134 | - mask[jizhun == 65536] = 1 | |
135 | - mask[jizhun != 65536] = 0 | |
136 | - mask2[jizhun == 65536] = 0 | |
137 | - mask2[jizhun != 65536] = 1 | |
138 | - # 掩膜计算 | |
139 | - for i, d in enumerate(empty_list): | |
140 | - empty_list[i] = empty_list[i] * mask + data[:, :, i] * mask2 | |
112 | + mask = numpy.zeros((height, width, 3), dtype=int) | |
113 | + mask_data = numpy.zeros((height, width, 3), dtype=int) | |
141 | 114 | |
142 | - for ii in [0, 1, 2]: | |
143 | - # opencv 颜色排序为GBR | |
144 | - pixel_array[:, :, 2 - ii] = empty_list[ii] | |
115 | + mask[data == 65536] = 1 | |
116 | + mask[data != 65536] = 0 | |
117 | + mask_data[data == 65536] = 0 | |
118 | + mask_data[data != 65536] = 1 | |
119 | + | |
120 | + # # 掩膜计算 | |
121 | + pixel_array = pixel_array * mask + data * mask_data | |
122 | + | |
123 | + # opencv 颜色排序为GBR | |
124 | + d1 = copy.copy(pixel_array[:,:,0]) | |
125 | + pixel_array[:, :, 0] = pixel_array[:,:,2] | |
126 | + pixel_array[:, :, 2] = d1 | |
145 | 127 | |
146 | 128 | |
147 | 129 | elif len(intersect_image) == 1: |
148 | 130 | # 该影像的服务器,随机选取一个 |
149 | 131 | image = intersect_image[0] |
150 | 132 | image_servers = image.server.split(",") |
151 | - indx = int(random.random() * len(image_servers)) | |
152 | - | |
153 | - image_server = image_servers[indx] | |
154 | - | |
155 | - pixel_array_t = self.get_data(zoo, image_server, image, extent, bands, height, width) | |
133 | + #判断可用服务器 | |
134 | + image_servers = [ser for ser in image_servers if ser in servers] | |
135 | + if len(image_servers) > 0: | |
136 | + indx = int(random.random() * len(image_servers)) | |
137 | + image_server = image_servers[indx] | |
138 | + else: | |
139 | + image_server = "None" | |
140 | + # image_server = image_servers[0] | |
141 | + bands = json.loads(image.band_view) | |
142 | + pixel_array_t:numpy.ndarray = self.get_data(image_server, image, extent, bands, height, width) | |
156 | 143 | pixel_array = numpy.zeros((height, width, 3), dtype=int) |
144 | + | |
157 | 145 | for ii in [0, 1, 2]: |
158 | 146 | # opencv 颜色排序为GBR |
159 | 147 | pixel_array[:, :, 2 - ii] = pixel_array_t[:, :, ii] |
160 | 148 | |
161 | - | |
162 | 149 | else: |
163 | 150 | # 结果矩阵 |
164 | 151 | pixel_array = numpy.zeros((height, width, 3), dtype=int) + 65536 |
165 | 152 | |
153 | + | |
166 | 154 | # 将图片生成在内存中,然后直接返回response |
167 | 155 | im_data = self.create_by_opencv(image_type, pixel_array, quality) |
168 | 156 | return Response(im_data, mimetype=image_type.lower()) |
169 | 157 | |
158 | + | |
170 | 159 | except Exception as e: |
171 | 160 | print(traceback.format_exc()) |
172 | 161 | result["state"] = -1 |
173 | 162 | result["message"] = e.__str__() |
174 | 163 | return result |
175 | 164 | |
165 | + def cache_data(self): | |
166 | + | |
167 | + from app import GLOBAL_DIC | |
168 | + | |
169 | + # 缓存zookeeper | |
170 | + zoo = GLOBAL_DIC.get("zookeeper") | |
171 | + if zoo is None: | |
172 | + zoo: KazooClient = KazooClient(hosts=configure.zookeeper, timeout=100) | |
173 | + zoo.start() | |
174 | + GLOBAL_DIC["zookeeper"] = zoo | |
175 | + else: | |
176 | + if not zoo.connected: | |
177 | + zoo.start() | |
178 | + | |
179 | + # 缓存数据服务器 | |
180 | + servers = GLOBAL_DIC.get("servers") | |
181 | + if servers is None: | |
182 | + servers = zoo.get_children("/rpc") | |
183 | + servers.append("本地服务器") | |
184 | + GLOBAL_DIC["servers"] = servers | |
185 | + GLOBAL_DIC["servers_updatetime"] = time.time() | |
186 | + else: | |
187 | + servers = GLOBAL_DIC.get("servers") | |
188 | + | |
189 | + # 更新缓存 | |
190 | + if time.time() - GLOBAL_DIC["servers_updatetime"] > 10: | |
191 | + servers = zoo.get_children("/rpc") | |
192 | + servers.append("本地服务器") | |
193 | + GLOBAL_DIC["servers"] = servers | |
194 | + GLOBAL_DIC["servers_updatetime"] = time.time() | |
195 | + | |
196 | + | |
197 | + # 缓存服务信息 | |
198 | + image_service_info = GLOBAL_DIC.get(self.guid) | |
199 | + if image_service_info is None or time.time() - GLOBAL_DIC.get("service_updatetime") > 20: | |
200 | + image_service: ImageService = ImageService.query.filter_by(guid=self.guid).one_or_none() | |
201 | + images = image_service.images.all() | |
202 | + scheme: TileScheme = TileScheme.query.filter_by(guid=image_service.scheme_guid).one_or_none() | |
203 | + GLOBAL_DIC[self.guid] = {"service": image_service, "images": images, "scheme": json.loads(scheme.parameter)} | |
204 | + GLOBAL_DIC["service_updatetime"] = time.time() | |
205 | + image_service_info = GLOBAL_DIC[self.guid] | |
206 | + | |
207 | + else: | |
208 | + image_service_info = GLOBAL_DIC[self.guid] | |
209 | + | |
210 | + return image_service_info,zoo,servers | |
211 | + | |
176 | 212 | def determine_level(self, xysize, origin_extent, extent, max_level): |
177 | 213 | ''' |
178 | 214 | 根据范围判断调用金字塔的哪一层 |
... | ... | @@ -195,10 +231,12 @@ class Api(ApiTemplate): |
195 | 231 | (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1]))) |
196 | 232 | return level |
197 | 233 | |
234 | + | |
198 | 235 | def create_by_opencv(self, image_type, pixel_array, quality): |
199 | 236 | |
200 | 237 | if image_type.__eq__("image/jpeg") or image_type.__eq__("image/jpg"): |
201 | 238 | r, buf = cv2.imencode(".jpg", pixel_array, [cv2.IMWRITE_JPEG_QUALITY, quality]) |
239 | + # r, buf = cv2.imencode(".jpg", pixel_array) | |
202 | 240 | image_out = buf.tobytes() |
203 | 241 | else: |
204 | 242 | height, width = pixel_array[:, :, 0].shape |
... | ... | @@ -208,17 +246,14 @@ class Api(ApiTemplate): |
208 | 246 | image_out = buf.tobytes() |
209 | 247 | return image_out |
210 | 248 | |
211 | - def get_data(self, zoo, image_server, image, extent, bands, height, width): | |
249 | + def get_data(self,image_server, image, extent, bands, height, width): | |
212 | 250 | |
213 | 251 | if image_server.__eq__("本地服务器"): |
214 | - data = self.get_local_wms_data(image, extent, bands, height, width) | |
252 | + data = self.get_local_wms_data2(image, extent, bands, height, width) | |
253 | + elif image_server.__eq__("None"): | |
254 | + data = numpy.zeros((height, width, 3), dtype=int) + 65536 | |
215 | 255 | else: |
216 | - ser = image_server | |
217 | - if zoo.exists("/rpc/{}".format(ser)): | |
218 | - data = self.get_remote_wms_data(ser,image, extent, bands, height, width) | |
219 | - else: | |
220 | - data = numpy.zeros((height, width, 3), dtype=int) + 65536 | |
221 | - | |
256 | + data = self.get_remote_wms_data(image_server,image, extent, bands, height, width) | |
222 | 257 | return data |
223 | 258 | |
224 | 259 | def get_remote_wms_data(self, image_server,image, extent, bands, height, width): |
... | ... | @@ -230,24 +265,93 @@ class Api(ApiTemplate): |
230 | 265 | :return: |
231 | 266 | ''' |
232 | 267 | |
233 | - | |
234 | 268 | #需要做thrift连接的缓存,连接池 |
269 | + thrift_connect = ThriftConnect(image_server) | |
270 | + image_extent = image.extent | |
271 | + | |
272 | + data = thrift_connect.client.getData(image.path, extent, json.loads(image_extent), bands, width, height) | |
273 | + | |
274 | + thrift_connect.close() | |
275 | + | |
276 | + data = gzip.decompress(data) | |
277 | + data = numpy.frombuffer(data, dtype='int64') | |
278 | + data = data.reshape((height, width, 3)) | |
279 | + | |
280 | + return data | |
281 | + | |
235 | 282 | |
283 | + def get_remote_wms_data_cpp(self, image_server,image, extent, bands, height, width): | |
284 | + ''' | |
285 | + 通过RPC获取远程数据 | |
286 | + :param image: | |
287 | + :param extent: | |
288 | + :param bands: | |
289 | + :return: | |
290 | + ''' | |
291 | + | |
292 | + #需要做thrift连接的缓存,连接池 | |
236 | 293 | thrift_connect = ThriftConnect(image_server) |
237 | - t1 = time.time() | |
238 | 294 | image_extent = image.extent |
239 | 295 | |
240 | 296 | data = thrift_connect.client.getData(image.path, extent, json.loads(image_extent), bands, width, height) |
241 | 297 | |
242 | 298 | thrift_connect.close() |
243 | 299 | |
244 | - # current_app.logger.info("time {}".format(time.time() - t1)) | |
300 | + return data | |
301 | + | |
302 | + def get_remote_wms_data_client(self,image_server,image, extent, bands, height, width): | |
303 | + ''' | |
304 | + 通过RPC获取远程数据 | |
305 | + :param image: | |
306 | + :param extent: | |
307 | + :param bands: | |
308 | + :return: | |
309 | + ''' | |
310 | + from app import GLOBAL_DIC | |
311 | + | |
312 | + # 缓存thrift_pool | |
313 | + thrift_pool = GLOBAL_DIC.get(image_server) | |
314 | + if thrift_pool is None: | |
315 | + thrift_pool = ThriftPool(image_server) | |
316 | + GLOBAL_DIC["image_server"] = thrift_pool | |
317 | + image_extent = image.extent | |
318 | + | |
319 | + client,transport = thrift_pool.get_client() | |
320 | + transport.open() | |
321 | + data = client.getData(image.path, extent, json.loads(image_extent), bands, width, height) | |
322 | + transport.close() | |
245 | 323 | data = gzip.decompress(data) |
246 | 324 | data = numpy.frombuffer(data, dtype='int64') |
247 | 325 | data = data.reshape((height, width, 3)) |
248 | 326 | |
249 | 327 | return data |
250 | 328 | |
329 | + # def get_remote_wms_data_c(self, image_server,image, extent, bands, height, width): | |
330 | + # ''' | |
331 | + # 通过RPC获取远程数据 | |
332 | + # :param image: | |
333 | + # :param extent: | |
334 | + # :param bands: | |
335 | + # :return: | |
336 | + # ''' | |
337 | + # | |
338 | + # #需要做thrift连接的缓存,连接池 | |
339 | + # thrift_connect = ThriftConnect_C(image_server) | |
340 | + # image_extent = image.extent | |
341 | + # | |
342 | + # data = thrift_connect.client.getData(image.path, extent, json.loads(image_extent), bands, width, height) | |
343 | + # | |
344 | + # thrift_connect.close() | |
345 | + # | |
346 | + # data = gzip.decompress(data) | |
347 | + # data = numpy.frombuffer(data, dtype='int64') | |
348 | + # | |
349 | + # | |
350 | + # data = data.reshape((height, width, 3)) | |
351 | + # | |
352 | + # return data | |
353 | + | |
354 | + | |
251 | 355 | def get_local_wms_data(self, image, extent, bands, height, width): |
252 | 356 | ''' |
253 | 357 | 获取本地数据 |
... | ... | @@ -259,20 +363,21 @@ class Api(ApiTemplate): |
259 | 363 | pixel_array = numpy.zeros((height, width, 3), dtype=int) |
260 | 364 | ceng = 0 |
261 | 365 | img: Dataset = gdal.Open(image.path, 0) |
262 | - t1 = time.time() | |
366 | + | |
367 | + | |
368 | + | |
263 | 369 | for band in bands: |
264 | 370 | |
265 | 371 | # 自决定金字塔等级 |
266 | 372 | xysize = [img.RasterXSize, img.RasterYSize] |
267 | 373 | |
268 | - origin_extent = image.extent | |
374 | + origin_extent = json.loads(image.extent) | |
269 | 375 | band_data: Band = img.GetRasterBand(band) |
270 | 376 | |
271 | 377 | max_level = band_data.GetOverviewCount() |
272 | 378 | |
273 | 379 | # 超出空间范围 |
274 | - if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[ | |
275 | - 3] or extent[3] < origin_extent[1]: | |
380 | + if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[3] or extent[3] < origin_extent[1]: | |
276 | 381 | empty = numpy.zeros((height, width), dtype=int) + 65536 |
277 | 382 | # 空间范围相交 |
278 | 383 | else: |
... | ... | @@ -351,10 +456,96 @@ class Api(ApiTemplate): |
351 | 456 | ceng += 1 |
352 | 457 | return pixel_array |
353 | 458 | |
459 | + def get_local_wms_data2(self, image, extent, bands, height, width): | |
460 | + ''' | |
461 | + 获取本地数据 | |
462 | + :param image: | |
463 | + :param extent: | |
464 | + :param bands: | |
465 | + :return: | |
466 | + ''' | |
467 | + pixel_array = numpy.zeros((height, width, 3), dtype=int) | |
468 | + ceng = 0 | |
469 | + img: Dataset = gdal.Open(image.path, 0) | |
470 | + | |
471 | + origin_extent = json.loads(image.extent) | |
472 | + | |
473 | + # 超出空间范围 | |
474 | + if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[3] or extent[ | |
475 | + 3] < origin_extent[1]: | |
476 | + empty = numpy.zeros((height, width,3), dtype=int) + 65536 | |
477 | + # 空间范围相交 | |
478 | + else: | |
479 | + | |
480 | + ox = img.RasterXSize | |
481 | + oy = img.RasterYSize | |
482 | + | |
483 | + # 网格大小 | |
484 | + grid_x = (origin_extent[2] - origin_extent[0]) / (ox * 1.0) | |
485 | + grid_y = (origin_extent[3] - origin_extent[1]) / (oy * 1.0) | |
486 | + | |
487 | + # 完全在影像范围内 | |
488 | + if extent[0] > origin_extent[0] and extent[1] > origin_extent[1] and extent[2] < \ | |
489 | + origin_extent[2] and extent[3] < origin_extent[3]: | |
490 | + | |
491 | + # 网格偏移量 | |
492 | + off_x = math.floor((extent[0] - origin_extent[0]) / grid_x) | |
493 | + off_y = math.floor((origin_extent[3] - extent[3]) / grid_y) | |
494 | + | |
495 | + # 截取后网格个数 | |
496 | + x_g = math.ceil((extent[2] - extent[0]) / grid_x) | |
497 | + | |
498 | + y_g = math.ceil((extent[3] - extent[1]) / grid_y) | |
499 | + | |
500 | + empty = img.ReadRaster(off_x, off_y, x_g, y_g,256,256,band_list=[1,2,3]) | |
501 | + img.ReadAsArray() | |
502 | + # 部分相交 | |
503 | + else: | |
504 | + | |
505 | + inter_extent = [0, 0, 0, 0] | |
506 | + inter_extent[0] = origin_extent[0] if origin_extent[0] > extent[0] else extent[0] | |
507 | + inter_extent[1] = origin_extent[1] if origin_extent[1] > extent[1] else extent[1] | |
508 | + inter_extent[2] = origin_extent[2] if origin_extent[2] < extent[2] else extent[2] | |
509 | + inter_extent[3] = origin_extent[3] if origin_extent[3] < extent[3] else extent[3] | |
510 | + | |
511 | + # 网格偏移量 | |
512 | + off_x = math.floor((inter_extent[0] - origin_extent[0]) / grid_x) | |
513 | + off_y = math.floor((origin_extent[3] - inter_extent[3]) / grid_y) | |
514 | + | |
515 | + # 截取后网格个数 | |
516 | + x_g = math.floor((inter_extent[2] - inter_extent[0]) / grid_x) | |
517 | + y_g = math.floor((inter_extent[3] - inter_extent[1]) / grid_y) | |
518 | + | |
519 | + # 相对于出图的偏移量 | |
520 | + | |
521 | + # 出图的网格大小 | |
522 | + out_grid_x = (extent[2] - extent[0]) / (width * 1.0) | |
523 | + out_grid_y = (extent[3] - extent[1]) / (height * 1.0) | |
524 | + | |
525 | + out_off_x = int(math.ceil((inter_extent[0] - extent[0]) / out_grid_x)) | |
526 | + out_off_y = int(math.ceil((extent[3] - inter_extent[3]) / out_grid_y)) | |
527 | + | |
528 | + out_x_g = int(math.floor((inter_extent[2] - inter_extent[0]) / out_grid_x)) | |
529 | + out_y_g = int(math.floor((inter_extent[3] - inter_extent[1]) / out_grid_y)) | |
530 | + | |
531 | + # 相交部分在出图的哪个位置 | |
532 | + | |
533 | + overview_raster: ndarray = img.ReadAsArray(off_x, off_y, x_g, y_g, out_x_g, | |
534 | + out_y_g) | |
535 | + | |
536 | + dat = numpy.zeros((height, width,3), dtype=int) + 65536 | |
537 | + dat[out_off_y:out_off_y + out_y_g, out_off_x:out_off_x + out_x_g] = overview_raster | |
538 | + empty = dat | |
539 | + | |
540 | + return empty | |
541 | + | |
354 | 542 | def determin_intersect(self, extent1, extent2): |
355 | - g1 = GeometryAdapter.bbox_2_polygon(extent1) | |
356 | - g2 = GeometryAdapter.bbox_2_polygon(extent2) | |
357 | - return g1.Intersect(g2) | |
543 | + if extent2[2] < extent1[0] or extent2[0] > extent1[2] or extent2[1] > extent1[ | |
544 | + 3] or extent2[3] < extent1[1]: | |
545 | + return False | |
546 | + else: | |
547 | + return True | |
548 | + | |
358 | 549 | |
359 | 550 | api_doc = { |
360 | 551 | "tags": ["影像接口"], | ... | ... |
app/modules/service/image/image_tile_mask.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: 4N | |
3 | +#createtime: 2021/3/24 | |
4 | +#email: nheweijun@sina.com | |
5 | + | |
6 | +from app.util import * | |
7 | +import traceback | |
8 | +from osgeo import gdal | |
9 | +from osgeo.gdal import * | |
10 | +from numpy import ndarray | |
11 | +import numpy | |
12 | +from flask import Response | |
13 | +import io | |
14 | +import os | |
15 | +from PIL import Image | |
16 | + | |
17 | +import time | |
18 | +import cv2 | |
19 | +from app.modules.service.image.models import ImageService,Image | |
20 | +from app.models import db,TileScheme | |
21 | +from app.util.component.ApiTemplate import ApiTemplate | |
22 | +import uuid | |
23 | +from app.util.component.SliceScheme import SliceScheme | |
24 | +from app.util.component.FileProcess import FileProcess | |
25 | +from app.util.component.ParameterUtil import ParameterUtil | |
26 | +from app.util.component.GeometryAdapter import GeometryAdapter | |
27 | +from app.util.component.Geometry2Raster import Geometry2Raster | |
28 | +import os | |
29 | +import json | |
30 | +from kazoo.client import KazooClient | |
31 | + | |
32 | +from threading import Thread | |
33 | + | |
34 | +from app.modules.service.image.util.ThriftConnect import ThriftConnect | |
35 | +from flask import current_app | |
36 | +import gzip | |
37 | +import random | |
38 | +class Api(ApiTemplate): | |
39 | + | |
40 | + api_name = "切片" | |
41 | + | |
42 | + def __init__(self,guid,level, row, col): | |
43 | + super().__init__() | |
44 | + self.guid = guid | |
45 | + self.level = level | |
46 | + self.row = row | |
47 | + self.col = col | |
48 | + | |
49 | + def process(self): | |
50 | + from app import GLOBAL_DIC | |
51 | + result = {} | |
52 | + parameter: dict = self.para | |
53 | + | |
54 | + | |
55 | + | |
56 | + | |
57 | + | |
58 | + try: | |
59 | + if parameter.get("guid"): | |
60 | + self.guid = parameter.get("guid") | |
61 | + | |
62 | + #缓存服务信息 | |
63 | + image_service_info = GLOBAL_DIC.get(self.guid) | |
64 | + if image_service_info is None: | |
65 | + image_service:ImageService = ImageService.query.filter_by(guid = self.guid).one_or_none() | |
66 | + images = image_service.images.all() | |
67 | + scheme:TileScheme = TileScheme.query.filter_by(guid=image_service.scheme_guid).one_or_none() | |
68 | + | |
69 | + # test mask | |
70 | + ring = ogr.Geometry(ogr.wkbLinearRing) | |
71 | + ring.AddPoint(111.62, 29) | |
72 | + ring.AddPoint(111.62, 29.03) | |
73 | + ring.AddPoint(111.727, 29.03) | |
74 | + ring.AddPoint(111.727, 29) | |
75 | + ring.AddPoint(111.62, 29) | |
76 | + # Create polygon | |
77 | + mask_poly = ogr.Geometry(ogr.wkbPolygon) | |
78 | + mask_poly.AddGeometry(ring) | |
79 | + | |
80 | + GLOBAL_DIC[self.guid] = {"service": image_service, "images": images, | |
81 | + "scheme": json.loads(scheme.parameter),"mask": | |
82 | + mask_poly} | |
83 | + | |
84 | + | |
85 | + image_service_info = GLOBAL_DIC[self.guid] | |
86 | + else: | |
87 | + image_service_info = GLOBAL_DIC[self.guid] | |
88 | + | |
89 | + zoo = GLOBAL_DIC.get("zookeeper") | |
90 | + if zoo is None: | |
91 | + zoo :KazooClient = KazooClient(hosts=configure.zookeeper, timeout=100) | |
92 | + zoo.start() | |
93 | + GLOBAL_DIC["zookeeper"] = zoo | |
94 | + else : | |
95 | + if not zoo.connected: | |
96 | + zoo.start() | |
97 | + | |
98 | + bands = [1, 2, 3] | |
99 | + | |
100 | + | |
101 | + # 转换参数 | |
102 | + parameter = ParameterUtil.to_lower(parameter) | |
103 | + | |
104 | + | |
105 | + if parameter.get("tilematrix"): | |
106 | + if parameter.get("tilematrix").__contains__(":"): | |
107 | + self.level = int(parameter.get("tilematrix").split(":")[-1]) | |
108 | + else: | |
109 | + self.level = int(parameter.get("tilematrix")) | |
110 | + if parameter.get("tilerow"): | |
111 | + self.row = int(parameter.get("tilerow")) | |
112 | + if parameter.get("tilecol"): | |
113 | + self.col = int(parameter.get("tilecol")) | |
114 | + | |
115 | + image_type = parameter.get("format") if parameter.get("format") else "image/png" | |
116 | + quality = int(parameter.get("quality")) if parameter.get("quality") else 30 | |
117 | + slice_para = image_service_info["scheme"] | |
118 | + extent = SliceScheme.get_polygon(slice_para, self.level, self.row, self.col) | |
119 | + | |
120 | + | |
121 | + height, width = 256,256 | |
122 | + | |
123 | + # 多线程获取分布式数据 | |
124 | + | |
125 | + intersect_image = [im for im in image_service_info["images"] if | |
126 | + self.determin_intersect(json.loads(im.extent), extent,image_service_info["mask"])] | |
127 | + | |
128 | + masker_raster = Geometry2Raster.convert(image_service_info["mask"],extent,height) | |
129 | + | |
130 | + if len(intersect_image) > 1: | |
131 | + | |
132 | + # 结果矩阵 | |
133 | + empty_list = [numpy.zeros((height, width), dtype=int) + 65536, | |
134 | + numpy.zeros((height, width), dtype=int) + 65536, | |
135 | + numpy.zeros((height, width), dtype=int) + 65536] | |
136 | + | |
137 | + pixel_array = numpy.zeros((height, width, 3), dtype=int) | |
138 | + thread_list = [] | |
139 | + | |
140 | + for image in intersect_image: | |
141 | + # 该影像的服务器,随机选取一个 | |
142 | + image_servers = image.server.split(",") | |
143 | + image_servers = [ser for ser in image_servers if zoo.exists("/rpc/{}".format(ser))] | |
144 | + if len(image_servers)>0: | |
145 | + indx = int(random.random() * len(image_servers)) | |
146 | + image_server = image_servers[indx] | |
147 | + else: | |
148 | + image_server = "None" | |
149 | + | |
150 | + thread: MyThread = MyThread(self.get_data, | |
151 | + args=(image_server, image, extent, bands, height, width)) | |
152 | + thread.start() | |
153 | + thread_list.append(thread) | |
154 | + | |
155 | + for thread in thread_list: | |
156 | + thread.join() | |
157 | + data = thread.get_result() | |
158 | + | |
159 | + # 掩膜在中央接口生成,合图 | |
160 | + mask = numpy.zeros((height, width), dtype=int) | |
161 | + mask2 = numpy.zeros((height, width), dtype=int) | |
162 | + jizhun = data[:, :, 0] | |
163 | + mask[jizhun == 65536] = 1 | |
164 | + mask[jizhun != 65536] = 0 | |
165 | + mask2[jizhun == 65536] = 0 | |
166 | + mask2[jizhun != 65536] = 1 | |
167 | + # 掩膜计算 | |
168 | + for i, d in enumerate(empty_list): | |
169 | + empty_list[i] = empty_list[i] * mask + data[:, :, i] * mask2 | |
170 | + | |
171 | + e = numpy.zeros((height, width), dtype=int) + 65536 | |
172 | + e_mask = numpy.zeros((height, width), dtype=int) | |
173 | + e_mask[masker_raster == 1] = 0 | |
174 | + e_mask[masker_raster == 0] = 1 | |
175 | + | |
176 | + for ii in [0, 1, 2]: | |
177 | + # opencv 颜色排序为GBR | |
178 | + # pixel_array[:, :, 2 - ii] = empty_list[ii] | |
179 | + #mask | |
180 | + pixel_array[:, :, 2 - ii] = e * e_mask + empty_list[ii] * masker_raster | |
181 | + | |
182 | + elif len(intersect_image) == 1: | |
183 | + # 该影像的服务器,随机选取一个 | |
184 | + image = intersect_image[0] | |
185 | + image_servers = image.server.split(",") | |
186 | + #判断可用服务器 | |
187 | + image_servers = [ser for ser in image_servers if zoo.exists("/rpc/{}".format(ser))] | |
188 | + if len(image_servers) > 0: | |
189 | + indx = int(random.random() * len(image_servers)) | |
190 | + image_server = image_servers[indx] | |
191 | + else: | |
192 | + image_server = "None" | |
193 | + pixel_array_t = self.get_data(image_server, image, extent, bands, height, width) | |
194 | + pixel_array = numpy.zeros((height, width, 3), dtype=int) | |
195 | + | |
196 | + e = numpy.zeros((height, width), dtype=int) + 65536 | |
197 | + e_mask = numpy.zeros((height, width), dtype=int) | |
198 | + e_mask[masker_raster == 1] = 0 | |
199 | + e_mask[masker_raster == 0] = 1 | |
200 | + | |
201 | + for ii in [0, 1, 2]: | |
202 | + # opencv 颜色排序为GBR | |
203 | + # pixel_array[:, :, 2 - ii] = pixel_array_t[:, :, ii] | |
204 | + pixel_array[:, :, 2 - ii] = e * e_mask + pixel_array_t[:, :, ii] * masker_raster | |
205 | + else: | |
206 | + # 结果矩阵 | |
207 | + pixel_array = numpy.zeros((height, width, 3), dtype=int) + 65536 | |
208 | + | |
209 | + | |
210 | + # 将图片生成在内存中,然后直接返回response | |
211 | + im_data = self.create_by_opencv(image_type, pixel_array, quality) | |
212 | + return Response(im_data, mimetype=image_type.lower()) | |
213 | + | |
214 | + except Exception as e: | |
215 | + print(traceback.format_exc()) | |
216 | + result["state"] = -1 | |
217 | + result["message"] = e.__str__() | |
218 | + return result | |
219 | + | |
220 | + def determine_level(self, xysize, origin_extent, extent, max_level): | |
221 | + ''' | |
222 | + 根据范围判断调用金字塔的哪一层 | |
223 | + :param xysize: | |
224 | + :param origin_extent: | |
225 | + :param extent: | |
226 | + :param max_level: | |
227 | + :return: | |
228 | + ''' | |
229 | + x = xysize[0] | |
230 | + y = xysize[1] | |
231 | + level = -1 | |
232 | + pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / ( | |
233 | + (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1]))) | |
234 | + while pixel > 100000 and level < max_level - 1: | |
235 | + level += 1 | |
236 | + x = x / 2 | |
237 | + y = y / 2 | |
238 | + pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / ( | |
239 | + (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1]))) | |
240 | + return level | |
241 | + | |
242 | + def create_by_opencv(self, image_type, pixel_array, quality): | |
243 | + | |
244 | + if image_type.__eq__("image/jpeg") or image_type.__eq__("image/jpg"): | |
245 | + r, buf = cv2.imencode(".jpg", pixel_array, [cv2.IMWRITE_JPEG_QUALITY, quality]) | |
246 | + image_out = buf.tobytes() | |
247 | + else: | |
248 | + height, width = pixel_array[:, :, 0].shape | |
249 | + four = numpy.zeros((height, width), dtype=int) + 255 | |
250 | + four[pixel_array[:, :, 0] == 65536] = 0 | |
251 | + r, buf = cv2.imencode(".png", numpy.dstack((pixel_array, four))) | |
252 | + image_out = buf.tobytes() | |
253 | + return image_out | |
254 | + | |
255 | + def get_data(self,image_server, image, extent, bands, height, width): | |
256 | + | |
257 | + if image_server.__eq__("本地服务器"): | |
258 | + data = self.get_local_wms_data(image, extent, bands, height, width) | |
259 | + elif image_server.__eq__("None"): | |
260 | + data = numpy.zeros((height, width, 3), dtype=int) + 65536 | |
261 | + else: | |
262 | + data = self.get_remote_wms_data(image_server,image, extent, bands, height, width) | |
263 | + return data | |
264 | + | |
265 | + def get_remote_wms_data(self, image_server,image, extent, bands, height, width): | |
266 | + ''' | |
267 | + 通过RPC获取远程数据 | |
268 | + :param image: | |
269 | + :param extent: | |
270 | + :param bands: | |
271 | + :return: | |
272 | + ''' | |
273 | + | |
274 | + #需要做thrift连接的缓存,连接池 | |
275 | + thrift_connect = ThriftConnect(image_server) | |
276 | + image_extent = image.extent | |
277 | + | |
278 | + data = thrift_connect.client.getData(image.path, extent, json.loads(image_extent), bands, width, height) | |
279 | + | |
280 | + thrift_connect.close() | |
281 | + | |
282 | + data = gzip.decompress(data) | |
283 | + data = numpy.frombuffer(data, dtype='int64') | |
284 | + data = data.reshape((height, width, 3)) | |
285 | + | |
286 | + return data | |
287 | + | |
288 | + def get_local_wms_data(self, image, extent, bands, height, width): | |
289 | + ''' | |
290 | + 获取本地数据 | |
291 | + :param image: | |
292 | + :param extent: | |
293 | + :param bands: | |
294 | + :return: | |
295 | + ''' | |
296 | + pixel_array = numpy.zeros((height, width, 3), dtype=int) | |
297 | + ceng = 0 | |
298 | + img: Dataset = gdal.Open(image.path, 0) | |
299 | + t1 = time.time() | |
300 | + for band in bands: | |
301 | + | |
302 | + # 自决定金字塔等级 | |
303 | + xysize = [img.RasterXSize, img.RasterYSize] | |
304 | + | |
305 | + origin_extent = image.extent | |
306 | + band_data: Band = img.GetRasterBand(band) | |
307 | + | |
308 | + max_level = band_data.GetOverviewCount() | |
309 | + | |
310 | + # 超出空间范围 | |
311 | + if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[ | |
312 | + 3] or extent[3] < origin_extent[1]: | |
313 | + empty = numpy.zeros((height, width), dtype=int) + 65536 | |
314 | + # 空间范围相交 | |
315 | + else: | |
316 | + image_level = self.determine_level(xysize, origin_extent, extent, max_level) | |
317 | + | |
318 | + if image_level == -1: | |
319 | + overview = band_data | |
320 | + else: | |
321 | + try: | |
322 | + overview: Band = band_data.GetOverview(image_level) | |
323 | + except: | |
324 | + raise Exception("该影像不存在该级别的金字塔数据!") | |
325 | + ox = overview.XSize | |
326 | + oy = overview.YSize | |
327 | + | |
328 | + # 网格大小 | |
329 | + grid_x = (origin_extent[2] - origin_extent[0]) / (ox * 1.0) | |
330 | + grid_y = (origin_extent[3] - origin_extent[1]) / (oy * 1.0) | |
331 | + | |
332 | + # 完全在影像范围内 | |
333 | + if extent[0] > origin_extent[0] and extent[1] > origin_extent[1] and extent[2] < \ | |
334 | + origin_extent[2] and extent[3] < origin_extent[3]: | |
335 | + | |
336 | + # 网格偏移量 | |
337 | + off_x = math.floor((extent[0] - origin_extent[0]) / grid_x) | |
338 | + off_y = math.floor((origin_extent[3] - extent[3]) / grid_y) | |
339 | + | |
340 | + # 截取后网格个数 | |
341 | + x_g = math.ceil((extent[2] - extent[0]) / grid_x) | |
342 | + | |
343 | + y_g = math.ceil((extent[3] - extent[1]) / grid_y) | |
344 | + | |
345 | + empty = overview.ReadAsArray(off_x, off_y, x_g, y_g, width, height) | |
346 | + | |
347 | + | |
348 | + # 部分相交 | |
349 | + else: | |
350 | + | |
351 | + inter_extent = [0, 0, 0, 0] | |
352 | + inter_extent[0] = origin_extent[0] if origin_extent[0] > extent[0] else extent[0] | |
353 | + inter_extent[1] = origin_extent[1] if origin_extent[1] > extent[1] else extent[1] | |
354 | + inter_extent[2] = origin_extent[2] if origin_extent[2] < extent[2] else extent[2] | |
355 | + inter_extent[3] = origin_extent[3] if origin_extent[3] < extent[3] else extent[3] | |
356 | + | |
357 | + # 网格偏移量 | |
358 | + off_x = math.floor((inter_extent[0] - origin_extent[0]) / grid_x) | |
359 | + off_y = math.floor((origin_extent[3] - inter_extent[3]) / grid_y) | |
360 | + | |
361 | + # 截取后网格个数 | |
362 | + x_g = math.floor((inter_extent[2] - inter_extent[0]) / grid_x) | |
363 | + y_g = math.floor((inter_extent[3] - inter_extent[1]) / grid_y) | |
364 | + | |
365 | + # 相对于出图的偏移量 | |
366 | + | |
367 | + # 出图的网格大小 | |
368 | + out_grid_x = (extent[2] - extent[0]) / (width * 1.0) | |
369 | + out_grid_y = (extent[3] - extent[1]) / (height * 1.0) | |
370 | + | |
371 | + out_off_x = int(math.ceil((inter_extent[0] - extent[0]) / out_grid_x)) | |
372 | + out_off_y = int(math.ceil((extent[3] - inter_extent[3]) / out_grid_y)) | |
373 | + | |
374 | + out_x_g = int(math.floor((inter_extent[2] - inter_extent[0]) / out_grid_x)) | |
375 | + out_y_g = int(math.floor((inter_extent[3] - inter_extent[1]) / out_grid_y)) | |
376 | + | |
377 | + # 相交部分在出图的哪个位置 | |
378 | + | |
379 | + overview_raster: ndarray = overview.ReadAsArray(off_x, off_y, x_g, y_g, out_x_g, | |
380 | + out_y_g) | |
381 | + | |
382 | + dat = numpy.zeros((height, width), dtype=int) + 65536 | |
383 | + dat[out_off_y:out_off_y + out_y_g, out_off_x:out_off_x + out_x_g] = overview_raster | |
384 | + | |
385 | + empty = dat | |
386 | + | |
387 | + pixel_array[:, :, ceng] = empty | |
388 | + ceng += 1 | |
389 | + return pixel_array | |
390 | + | |
391 | + | |
392 | + def determin_intersect(self, extent1, extent2, mask): | |
393 | + g1 = GeometryAdapter.bbox_2_polygon(extent1) | |
394 | + g2 = GeometryAdapter.bbox_2_polygon(extent2) | |
395 | + if g1.Intersect(g2): | |
396 | + return g2.Intersect(mask) | |
397 | + else: | |
398 | + return False | |
399 | + | |
400 | + api_doc = { | |
401 | + "tags": ["影像接口"], | |
402 | + "parameters": [ | |
403 | + {"name": "guid", | |
404 | + "in": "formData", | |
405 | + "type": "string"}, | |
406 | + {"name": "tilematrix", | |
407 | + "in": "formData", | |
408 | + "type": "string"}, | |
409 | + {"name": "tilerow", | |
410 | + "in": "formData", | |
411 | + "type": "string"}, | |
412 | + {"name": "tilecol", | |
413 | + "in": "formData", | |
414 | + "type": "string"}, | |
415 | + {"name": "format", | |
416 | + "in": "formData", | |
417 | + "type": "string"}, | |
418 | + {"name": "quality", | |
419 | + "in": "formData", | |
420 | + "type": "string"} | |
421 | + | |
422 | + ], | |
423 | + "responses": { | |
424 | + 200: { | |
425 | + "schema": { | |
426 | + "properties": { | |
427 | + } | |
428 | + } | |
429 | + } | |
430 | + } | |
431 | + } | |
432 | + | |
433 | +class MyThread(Thread): | |
434 | + def __init__(self,func,args=()): | |
435 | + super(MyThread,self).__init__() | |
436 | + self.func = func | |
437 | + self.args = args | |
438 | + def run(self): | |
439 | + self.result = self.func(*self.args) | |
440 | + def get_result(self): | |
441 | + try: | |
442 | + return self.result | |
443 | + except Exception: | |
444 | + return None | |
445 | + | |
446 | + | |
447 | + | ... | ... |
... | ... | @@ -16,7 +16,7 @@ import cv2 |
16 | 16 | from app.modules.service.image.models import ImageService |
17 | 17 | from app.util.component.ApiTemplate import ApiTemplate |
18 | 18 | from app.util.component.GeometryAdapter import GeometryAdapter |
19 | -from app.modules.service.image.util.ThriftConnect import ThriftConnect | |
19 | +from app.modules.service.image.util.ThriftConnect import ThriftConnect,ThriftPool | |
20 | 20 | from app.util.component.ParameterUtil import ParameterUtil |
21 | 21 | import json |
22 | 22 | from kazoo.client import KazooClient |
... | ... | @@ -30,7 +30,7 @@ class Api(ApiTemplate): |
30 | 30 | api_name = "WMS" |
31 | 31 | |
32 | 32 | def process(self): |
33 | - from app import GLOBAL_DIC | |
33 | + | |
34 | 34 | |
35 | 35 | result = {} |
36 | 36 | parameter: dict = self.para |
... | ... | @@ -38,41 +38,21 @@ class Api(ApiTemplate): |
38 | 38 | try: |
39 | 39 | |
40 | 40 | parameter = ParameterUtil.to_lower(parameter) |
41 | - guid = parameter.get("guid") | |
41 | + self.guid = parameter.get("guid") | |
42 | 42 | bbox = parameter.get("bbox") |
43 | 43 | width = int(parameter.get("width")) if parameter.get("width") else 256 |
44 | 44 | height = int(parameter.get("height")) if parameter.get("height") else 256 |
45 | 45 | image_type = parameter.get("format") if parameter.get("format") else "image/png" |
46 | 46 | quality = int(parameter.get("quality")) if parameter.get("quality") else 30 |
47 | 47 | |
48 | - | |
49 | - #缓存起来 | |
50 | - #缓存服务信息 | |
51 | - image_service_info = GLOBAL_DIC.get(guid) | |
52 | - if image_service_info is None: | |
53 | - image_service:ImageService = ImageService.query.filter_by(guid=guid).one_or_none() | |
54 | - images = image_service.images.all() | |
55 | - GLOBAL_DIC[guid] = {"service":image_service,"images":images} | |
56 | - image_service_info = GLOBAL_DIC[guid] | |
57 | - else: | |
58 | - image_service_info = GLOBAL_DIC[guid] | |
59 | - | |
48 | + image_service_info, zoo, servers = self.cache_data() | |
60 | 49 | |
61 | 50 | re = parameter.get("request") |
62 | - | |
63 | 51 | if re and re.__eq__("GetCapabilities"): |
64 | 52 | return self.get_capabilities(image_service_info["service"]) |
65 | 53 | |
66 | - zoo = GLOBAL_DIC.get("zookeeper") | |
67 | - if zoo is None: | |
68 | - zoo :KazooClient = KazooClient(hosts=configure.zookeeper, timeout=100) | |
69 | - zoo.start() | |
70 | - GLOBAL_DIC["zookeeper"] = zoo | |
71 | - else : | |
72 | - if not zoo.connected: | |
73 | - zoo.start() | |
74 | 54 | |
75 | - bands = [1, 2, 3] | |
55 | + # bands = [1, 2, 3] | |
76 | 56 | |
77 | 57 | extent = [float(x) for x in bbox.split(",")] |
78 | 58 | |
... | ... | @@ -91,10 +71,14 @@ class Api(ApiTemplate): |
91 | 71 | for image in intersect_image: |
92 | 72 | #该影像的服务器,随机选取一个 |
93 | 73 | image_servers = image.server.split(",") |
94 | - indx = int(random.random()*len(image_servers)) | |
95 | - image_server = image_servers[indx] | |
96 | - | |
97 | - thread: MyThread = MyThread(self.get_data, args=(zoo,image_server,image,extent,bands,height,width)) | |
74 | + image_servers = [ser for ser in image_servers if ser in servers] | |
75 | + if len(image_servers)>0: | |
76 | + indx = int(random.random() * len(image_servers)) | |
77 | + image_server = image_servers[indx] | |
78 | + else: | |
79 | + image_server = "None" | |
80 | + bands = json.loads(image.band_view) | |
81 | + thread: MyThread = MyThread(self.get_data, args=(image_server,image,extent,bands,height,width)) | |
98 | 82 | thread.start() |
99 | 83 | thread_list.append(thread) |
100 | 84 | |
... | ... | @@ -124,9 +108,15 @@ class Api(ApiTemplate): |
124 | 108 | # 该影像的服务器,随机选取一个 |
125 | 109 | image = intersect_image[0] |
126 | 110 | image_servers = image.server.split(",") |
127 | - indx = int(random.random() * len(image_servers)) | |
128 | - image_server = image_servers[indx] | |
129 | - pixel_array_t = self.get_data(zoo,image_server,image,extent,bands,height,width) | |
111 | + image_servers = [ser for ser in image_servers if ser in servers] | |
112 | + if len(image_servers) > 0: | |
113 | + indx = int(random.random() * len(image_servers)) | |
114 | + image_server = image_servers[indx] | |
115 | + else: | |
116 | + image_server = "None" | |
117 | + | |
118 | + bands = json.loads(image.band_view) | |
119 | + pixel_array_t = self.get_data(image_server,image,extent,bands,height,width) | |
130 | 120 | pixel_array = numpy.zeros((height, width, 3), dtype=int) |
131 | 121 | for ii in [0, 1, 2]: |
132 | 122 | # opencv 颜色排序为GBR |
... | ... | @@ -148,6 +138,55 @@ class Api(ApiTemplate): |
148 | 138 | result["message"] = e.__str__() |
149 | 139 | return result |
150 | 140 | |
141 | + | |
142 | + def cache_data(self): | |
143 | + | |
144 | + from app import GLOBAL_DIC | |
145 | + | |
146 | + # 缓存zookeeper | |
147 | + zoo = GLOBAL_DIC.get("zookeeper") | |
148 | + if zoo is None: | |
149 | + zoo: KazooClient = KazooClient(hosts=configure.zookeeper, timeout=100) | |
150 | + zoo.start() | |
151 | + GLOBAL_DIC["zookeeper"] = zoo | |
152 | + else: | |
153 | + if not zoo.connected: | |
154 | + zoo.start() | |
155 | + | |
156 | + # 缓存数据服务器 | |
157 | + servers = GLOBAL_DIC.get("servers") | |
158 | + if servers is None: | |
159 | + servers = zoo.get_children("/rpc") | |
160 | + servers.append("本地服务器") | |
161 | + GLOBAL_DIC["servers"] = servers | |
162 | + GLOBAL_DIC["servers_updatetime"] = time.time() | |
163 | + else: | |
164 | + servers = GLOBAL_DIC.get("servers") | |
165 | + | |
166 | + # 更新缓存 | |
167 | + if time.time() - GLOBAL_DIC["servers_updatetime"] > 10: | |
168 | + servers = zoo.get_children("/rpc") | |
169 | + servers.append("本地服务器") | |
170 | + GLOBAL_DIC["servers"] = servers | |
171 | + GLOBAL_DIC["servers_updatetime"] = time.time() | |
172 | + | |
173 | + | |
174 | + # 缓存服务信息 | |
175 | + image_service_info = GLOBAL_DIC.get(self.guid) | |
176 | + if image_service_info is None or time.time() - GLOBAL_DIC.get("service_updatetime") > 20: | |
177 | + image_service: ImageService = ImageService.query.filter_by(guid=self.guid).one_or_none() | |
178 | + images = image_service.images.all() | |
179 | + GLOBAL_DIC[self.guid] = {"service": image_service, "images": images} | |
180 | + GLOBAL_DIC["service_updatetime"] = time.time() | |
181 | + image_service_info = GLOBAL_DIC[self.guid] | |
182 | + | |
183 | + else: | |
184 | + image_service_info = GLOBAL_DIC[self.guid] | |
185 | + | |
186 | + return image_service_info,zoo,servers | |
187 | + | |
188 | + | |
189 | + | |
151 | 190 | def determine_level(self,xysize,origin_extent,extent,max_level): |
152 | 191 | ''' |
153 | 192 | 根据范围判断调用金字塔的哪一层 |
... | ... | @@ -182,17 +221,14 @@ class Api(ApiTemplate): |
182 | 221 | image_out = buf.tobytes() |
183 | 222 | return image_out |
184 | 223 | |
185 | - def get_data(self,zoo,image_server,image,extent,bands,height,width): | |
224 | + def get_data(self,image_server, image, extent, bands, height, width): | |
186 | 225 | |
187 | 226 | if image_server.__eq__("本地服务器"): |
188 | 227 | data = self.get_local_wms_data(image, extent, bands, height, width) |
228 | + elif image_server.__eq__("None"): | |
229 | + data = numpy.zeros((height, width, 3), dtype=int) + 65536 | |
189 | 230 | else: |
190 | - ser = image_server | |
191 | - if zoo.exists("/rpc/{}".format(ser)): | |
192 | - data = self.get_remote_wms_data(image_server,image, extent, bands, height, width) | |
193 | - else: | |
194 | - data = numpy.zeros((height, width, 3), dtype=int) + 65536 | |
195 | - | |
231 | + data = self.get_remote_wms_data(image_server,image, extent, bands, height, width) | |
196 | 232 | return data |
197 | 233 | |
198 | 234 | |
... | ... | @@ -206,7 +242,6 @@ class Api(ApiTemplate): |
206 | 242 | :return: |
207 | 243 | ''' |
208 | 244 | thrift_connect = ThriftConnect(image_server) |
209 | - t1 = time.time() | |
210 | 245 | image_extent = image.extent |
211 | 246 | |
212 | 247 | data = thrift_connect.client.getData(image.path, extent, json.loads(image_extent), bands,width,height) |
... | ... | @@ -219,6 +254,33 @@ class Api(ApiTemplate): |
219 | 254 | |
220 | 255 | return data |
221 | 256 | |
257 | + def get_remote_wms_data_client(self,image_server,image, extent, bands, height, width): | |
258 | + ''' | |
259 | + 通过RPC获取远程数据 | |
260 | + :param image: | |
261 | + :param extent: | |
262 | + :param bands: | |
263 | + :return: | |
264 | + ''' | |
265 | + from app import GLOBAL_DIC | |
266 | + | |
267 | + # 缓存thrift_pool | |
268 | + thrift_pool = GLOBAL_DIC.get(image_server) | |
269 | + if thrift_pool is None: | |
270 | + thrift_pool = ThriftPool(image_server) | |
271 | + GLOBAL_DIC["image_server"] = thrift_pool | |
272 | + client = thrift_pool.get_client() | |
273 | + | |
274 | + image_extent = image.extent | |
275 | + | |
276 | + data = client.getData(image.path, extent, json.loads(image_extent), bands, width, height) | |
277 | + | |
278 | + data = gzip.decompress(data) | |
279 | + data = numpy.frombuffer(data, dtype='int64') | |
280 | + data = data.reshape((height, width, 3)) | |
281 | + | |
282 | + return data | |
283 | + | |
222 | 284 | def get_local_wms_data(self,image,extent,bands,height,width): |
223 | 285 | ''' |
224 | 286 | 获取本地数据 |
... | ... | @@ -236,7 +298,7 @@ class Api(ApiTemplate): |
236 | 298 | # 自决定金字塔等级 |
237 | 299 | xysize = [img.RasterXSize, img.RasterYSize] |
238 | 300 | |
239 | - origin_extent = image.extent | |
301 | + origin_extent = json.loads(image.extent) | |
240 | 302 | band_data: Band = img.GetRasterBand(band) |
241 | 303 | |
242 | 304 | |
... | ... | @@ -244,8 +306,7 @@ class Api(ApiTemplate): |
244 | 306 | max_level = band_data.GetOverviewCount() |
245 | 307 | |
246 | 308 | # 超出空间范围 |
247 | - if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[ | |
248 | - 3] or extent[3] < origin_extent[1]: | |
309 | + if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[3] or extent[3] < origin_extent[1]: | |
249 | 310 | empty = numpy.zeros((height,width), dtype=int) + 65536 |
250 | 311 | # 空间范围相交 |
251 | 312 | else: |
... | ... | @@ -324,10 +385,12 @@ class Api(ApiTemplate): |
324 | 385 | ceng += 1 |
325 | 386 | return pixel_array |
326 | 387 | |
327 | - def determin_intersect(self,extent1,extent2): | |
328 | - g1 = GeometryAdapter.bbox_2_polygon(extent1) | |
329 | - g2 = GeometryAdapter.bbox_2_polygon(extent2) | |
330 | - return g1.Intersect(g2) | |
388 | + def determin_intersect(self, extent1, extent2): | |
389 | + if extent2[2] < extent1[0] or extent2[0] > extent1[2] or extent2[1] > extent1[ | |
390 | + 3] or extent2[3] < extent1[1]: | |
391 | + return False | |
392 | + else: | |
393 | + return True | |
331 | 394 | |
332 | 395 | def get_capabilities(self,image_service:ImageService): |
333 | 396 | ... | ... |
... | ... | @@ -3,13 +3,13 @@ |
3 | 3 | #createtime: 2021/9/26 |
4 | 4 | #email: nheweijun@sina.com |
5 | 5 | |
6 | -from app.modules.service.image.tutorial.ttypes import RasterData | |
6 | +from app.modules.service.image.tutorial2.ttypes import RasterData | |
7 | 7 | |
8 | 8 | from thrift.transport import TSocket |
9 | 9 | from thrift.transport import TTransport |
10 | 10 | from thrift.protocol import TBinaryProtocol |
11 | 11 | from app.modules.service.image.ImageDataService import ImageDataService |
12 | -from app.modules.service.image.tutorial import Calculator | |
12 | +from app.modules.service.image.tutorial2 import Calculator | |
13 | 13 | |
14 | 14 | from struct import Struct |
15 | 15 | ... | ... |
... | ... | @@ -16,15 +16,15 @@ else: |
16 | 16 | from thrift.transport import TTransport, TSocket, TSSLSocket, THttpClient |
17 | 17 | from thrift.protocol.TBinaryProtocol import TBinaryProtocol |
18 | 18 | |
19 | -from . import Calculator | |
20 | -from .ttypes import * | |
19 | +from tutorial import Calculator | |
20 | +from tutorial.ttypes import * | |
21 | 21 | |
22 | 22 | if len(sys.argv) <= 1 or sys.argv[1] == '--help': |
23 | 23 | print('') |
24 | 24 | print('Usage: ' + sys.argv[0] + ' [-h host[:port]] [-u url] [-f[ramed]] [-s[sl]] [-novalidate] [-ca_certs certs] [-keyfile keyfile] [-certfile certfile] function [arg1 [arg2...]]') |
25 | 25 | print('') |
26 | 26 | print('Functions:') |
27 | - print(' RasterData getData(string path, queryRange, originRange, bands, i32 width, i32 height)') | |
27 | + print(' getData(string path, queryRange, originRange, bands, i32 width, i32 height)') | |
28 | 28 | print(' Raster getInfo(string path)') |
29 | 29 | print(' bool buildOverview(string path)') |
30 | 30 | print(' getImageList(string path)') | ... | ... |
... | ... | @@ -505,9 +505,18 @@ class getData_result(object): |
505 | 505 | if ftype == TType.STOP: |
506 | 506 | break |
507 | 507 | if fid == 0: |
508 | - if ftype == TType.STRUCT: | |
509 | - self.success = RasterData() | |
510 | - self.success.read(iprot) | |
508 | + if ftype == TType.LIST: | |
509 | + self.success = [] | |
510 | + (_etype59, _size56) = iprot.readListBegin() | |
511 | + for _i60 in range(_size56): | |
512 | + _elem61 = [] | |
513 | + (_etype65, _size62) = iprot.readListBegin() | |
514 | + for _i66 in range(_size62): | |
515 | + _elem67 = iprot.readI16() | |
516 | + _elem61.append(_elem67) | |
517 | + iprot.readListEnd() | |
518 | + self.success.append(_elem61) | |
519 | + iprot.readListEnd() | |
511 | 520 | else: |
512 | 521 | iprot.skip(ftype) |
513 | 522 | else: |
... | ... | @@ -521,8 +530,14 @@ class getData_result(object): |
521 | 530 | return |
522 | 531 | oprot.writeStructBegin('getData_result') |
523 | 532 | if self.success is not None: |
524 | - oprot.writeFieldBegin('success', TType.STRUCT, 0) | |
525 | - self.success.write(oprot) | |
533 | + oprot.writeFieldBegin('success', TType.LIST, 0) | |
534 | + oprot.writeListBegin(TType.LIST, len(self.success)) | |
535 | + for iter68 in self.success: | |
536 | + oprot.writeListBegin(TType.I16, len(iter68)) | |
537 | + for iter69 in iter68: | |
538 | + oprot.writeI16(iter69) | |
539 | + oprot.writeListEnd() | |
540 | + oprot.writeListEnd() | |
526 | 541 | oprot.writeFieldEnd() |
527 | 542 | oprot.writeFieldStop() |
528 | 543 | oprot.writeStructEnd() |
... | ... | @@ -542,7 +557,7 @@ class getData_result(object): |
542 | 557 | return not (self == other) |
543 | 558 | all_structs.append(getData_result) |
544 | 559 | getData_result.thrift_spec = ( |
545 | - (0, TType.STRUCT, 'success', [RasterData, None], None, ), # 0 | |
560 | + (0, TType.LIST, 'success', (TType.LIST, (TType.I16, None, False), False), None, ), # 0 | |
546 | 561 | ) |
547 | 562 | |
548 | 563 | |
... | ... | @@ -878,11 +893,11 @@ class getImageList_result(object): |
878 | 893 | if fid == 0: |
879 | 894 | if ftype == TType.LIST: |
880 | 895 | self.success = [] |
881 | - (_etype59, _size56) = iprot.readListBegin() | |
882 | - for _i60 in range(_size56): | |
883 | - _elem61 = Image() | |
884 | - _elem61.read(iprot) | |
885 | - self.success.append(_elem61) | |
896 | + (_etype73, _size70) = iprot.readListBegin() | |
897 | + for _i74 in range(_size70): | |
898 | + _elem75 = Image() | |
899 | + _elem75.read(iprot) | |
900 | + self.success.append(_elem75) | |
886 | 901 | iprot.readListEnd() |
887 | 902 | else: |
888 | 903 | iprot.skip(ftype) |
... | ... | @@ -899,8 +914,8 @@ class getImageList_result(object): |
899 | 914 | if self.success is not None: |
900 | 915 | oprot.writeFieldBegin('success', TType.LIST, 0) |
901 | 916 | oprot.writeListBegin(TType.STRUCT, len(self.success)) |
902 | - for iter62 in self.success: | |
903 | - iter62.write(oprot) | |
917 | + for iter76 in self.success: | |
918 | + iter76.write(oprot) | |
904 | 919 | oprot.writeListEnd() |
905 | 920 | oprot.writeFieldEnd() |
906 | 921 | oprot.writeFieldStop() | ... | ... |
... | ... | @@ -9,21 +9,55 @@ |
9 | 9 | from thrift.transport import TSocket |
10 | 10 | from thrift.transport import TTransport |
11 | 11 | from thrift.protocol import TBinaryProtocol |
12 | + | |
13 | +from app.modules.service.image.tutorial import Calculator | |
12 | 14 | from app.modules.service.image.ImageDataService import ImageDataService |
13 | -from . import Calculator | |
15 | +import time | |
16 | + | |
17 | +def test1(): | |
18 | + | |
19 | + host = "172.26.60.100" | |
20 | + port = 8850 | |
21 | + | |
22 | + transport: TSocket = TSocket.TSocket(host, port) | |
23 | + transport = TTransport.TBufferedTransport(transport) | |
24 | + protocol = TBinaryProtocol.TBinaryProtocol(transport) | |
25 | + client = Calculator.Client(protocol) | |
26 | + | |
27 | + | |
28 | + transport.open() | |
29 | + import sys | |
30 | + test = client.getData("江南_01.tif",[1340.27, -1911.31, 4351.79, 5410.6],[1340.27, -1911.31, 4351.79, 5410.6],[3,2,1],768,768) | |
31 | + print(sys.getsizeof(test[1])) | |
32 | + # print(test) | |
33 | + | |
34 | +def test2(): | |
35 | + host = "172.26.60.100" | |
36 | + port = 9090 | |
14 | 37 | |
15 | -from struct import Struct | |
38 | + transport: TSocket = TSocket.TSocket(host, port) | |
39 | + transport = TTransport.TBufferedTransport(transport) | |
40 | + protocol = TBinaryProtocol.TBinaryProtocol(transport) | |
41 | + client = ImageDataService.Client(protocol) | |
16 | 42 | |
17 | -host = 1 | |
18 | -port = 9090 | |
19 | -transport: TSocket = TSocket.TSocket(host, port) | |
20 | -transport = TTransport.TBufferedTransport(transport) | |
21 | -protocol = TBinaryProtocol.TBinaryProtocol(transport) | |
43 | + transport.open() | |
22 | 44 | |
23 | -client = Calculator.Client(protocol) | |
45 | + test = client.getData("/usr/src/data/江南_01.tif", [1340.27, -1911.31, 4351.79, 5410.6], [1340.27, -1911.31, 4351.79, 5410.6], | |
46 | + [1,2,3], 768, 768) | |
24 | 47 | |
48 | + import gzip,numpy | |
49 | + data = gzip.decompress(test) | |
50 | + # data = numpy.frombuffer(data, dtype='int64') | |
51 | + # data = data.reshape((768, 768, 3)) | |
25 | 52 | |
26 | -transport.open() | |
53 | + import sys | |
54 | + print(sys.getsizeof(data)) | |
55 | + # print(test) | |
27 | 56 | |
28 | -test = client.getData("江南_01.tif",[1340.27, -1911.31, 4351.79, 5410.6],[1340.27, -1911.31, 4351.79, 5410.6],[3,2,1],768,768) | |
29 | -print(type(test)) | |
\ No newline at end of file | ||
57 | +if __name__ == '__main__': | |
58 | + t1 = time.time() | |
59 | + # test1() | |
60 | + print(time.time()-t1) | |
61 | + t2 = time.time() | |
62 | + test2() | |
63 | + print(time.time()-t2) | ... | ... |
... | ... | @@ -19,14 +19,64 @@ class ThriftConnect: |
19 | 19 | def __init__(self,data_server): |
20 | 20 | host = data_server.split(":")[0] |
21 | 21 | port = int(data_server.split(":")[1]) |
22 | + socket: TSocket = TSocket.TSocket(host, port) | |
23 | + self.transport = TTransport.TBufferedTransport(socket) | |
24 | + protocol = TBinaryProtocol.TBinaryProtocol(self.transport) | |
25 | + self.client = ImageDataService.Client(protocol) | |
26 | + self.transport.open() | |
27 | + | |
28 | + def close(self): | |
29 | + self.transport.close() | |
30 | + | |
31 | +class ThriftConnectCpp: | |
32 | + ''' | |
33 | + thrift连接类 | |
34 | + ''' | |
35 | + | |
36 | + client = None | |
37 | + transport = None | |
38 | + | |
39 | + def __init__(self,data_server): | |
40 | + host = data_server.split(":")[0] | |
41 | + port = int(data_server.split(":")[1]) | |
22 | 42 | self.transport: TSocket = TSocket.TSocket(host, port) |
23 | 43 | self.transport = TTransport.TBufferedTransport(self.transport) |
24 | 44 | protocol = TBinaryProtocol.TBinaryProtocol(self.transport) |
25 | - self.client = ImageDataService.Client(protocol) | |
45 | + # self.client = ImageDataService.Client(protocol) | |
26 | 46 | self.transport.open() |
27 | 47 | |
28 | 48 | def close(self): |
29 | 49 | self.transport.close() |
30 | 50 | |
31 | 51 | class ThriftPool: |
32 | - pass | |
\ No newline at end of file | ||
52 | + ''' | |
53 | + thrift线程池 | |
54 | + ''' | |
55 | + clients = [] | |
56 | + transports = [] | |
57 | + host = None | |
58 | + port = None | |
59 | + index = -1 | |
60 | + | |
61 | + def __init__(self,data_server): | |
62 | + self.host = data_server.split(":")[0] | |
63 | + self.port = int(data_server.split(":")[1]) | |
64 | + | |
65 | + def get_client(self): | |
66 | + if len(self.clients) < 20: | |
67 | + socket: TSocket = TSocket.TSocket(self.host, self.port) | |
68 | + transport = TTransport.TBufferedTransport(socket) | |
69 | + protocol = TBinaryProtocol.TBinaryProtocol(transport) | |
70 | + client = ImageDataService.Client(protocol) | |
71 | + self.clients.append(client) | |
72 | + self.transports.append(transport) | |
73 | + return client,transport | |
74 | + else: | |
75 | + self.index += 1 | |
76 | + if self.index == 20: | |
77 | + self.index = 0 | |
78 | + return self.clients[self.index],self.transports[self.index] | |
79 | + | |
80 | + | |
81 | + def close(self): | |
82 | + pass | |
\ No newline at end of file | ... | ... |
... | ... | @@ -24,6 +24,15 @@ class Api(ApiTemplate): |
24 | 24 | # extent = [float(x) for x in data.get("extent").split(",")] if data.get("extent") else [0,0,0,0] |
25 | 25 | # top_left = [float(x) for x in data.get("top_left").split(",")] if data.get("top_left") else [0, 0] |
26 | 26 | |
27 | + paramenter = {} | |
28 | + for l_dict in json.loads(data.get("levels")): | |
29 | + paramenter[str(l_dict["level"])] = {"resolution":l_dict["resolution"],"scale":l_dict["scale"]} | |
30 | + paramenter["cols"] = int(data.get("cols")) | |
31 | + paramenter["rows"] = int(data.get("rows")) | |
32 | + paramenter["dpi"] = int(data.get("dpi")) | |
33 | + paramenter["wkt"] = data.get("crs_wkt") | |
34 | + paramenter["x"] = eval(data.get("top_left").split(",")[0]) | |
35 | + paramenter["y"] = eval(data.get("top_left").split(",")[1]) | |
27 | 36 | |
28 | 37 | |
29 | 38 | guid = uuid.uuid1().__str__() |
... | ... | @@ -46,7 +55,7 @@ class Api(ApiTemplate): |
46 | 55 | rows = int(data.get("rows")), |
47 | 56 | cols = int(data.get("cols")), |
48 | 57 | update_time = datetime.datetime.now(), |
49 | - parameter=json.dumps(json.loads(data.get("parameter"))) | |
58 | + parameter=json.dumps(paramenter) | |
50 | 59 | ) |
51 | 60 | |
52 | 61 | db.session.add(tile_scheme) |
... | ... | @@ -92,9 +101,9 @@ class Api(ApiTemplate): |
92 | 101 | {"name": "levels", |
93 | 102 | "in": "formData", |
94 | 103 | "type": "string"}, |
95 | - {"name": "parameter", | |
96 | - "in": "formData", | |
97 | - "type": "string"}, | |
104 | + # {"name": "parameter", | |
105 | + # "in": "formData", | |
106 | + # "type": "string"}, | |
98 | 107 | |
99 | 108 | ], |
100 | 109 | "responses": { | ... | ... |
... | ... | @@ -34,6 +34,128 @@ class Api(ApiTemplate): |
34 | 34 | api_doc = { |
35 | 35 | "tags": ["服务接口"], |
36 | 36 | "parameters": [ |
37 | + | |
38 | + | |
39 | + {"name": "name", | |
40 | + "in": "formData", | |
41 | + "type": "string", | |
42 | + "required": "true", | |
43 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
44 | + {"name": "alias", | |
45 | + "in": "formData", | |
46 | + "type": "string", | |
47 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
48 | + {"name": "description", | |
49 | + "in": "formData", | |
50 | + "type": "string", | |
51 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
52 | + | |
53 | + {"name": "catalog_guid", | |
54 | + "in": "formData", | |
55 | + "type": "string", | |
56 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
57 | + | |
58 | + # 影像参数 | |
59 | + {"name": "guids", | |
60 | + "in": "formData", | |
61 | + "type": "string", | |
62 | + "description": "[影像WMS,影像WMTS]影像guids,以英文逗号相隔"}, | |
63 | + {"name": "scheme_guid", | |
64 | + "in": "formData", | |
65 | + "type": "string", | |
66 | + "description": "[WMTS,影像WMTS]切片方案"}, | |
67 | + | |
68 | + # WMTS参数 | |
69 | + {"name": "overview", | |
70 | + "in": "formData", | |
71 | + "type": "string", | |
72 | + "description": "[WMTS]缩略图"}, | |
73 | + {"name": "wmts_type", | |
74 | + "in": "formData", | |
75 | + "type": "string", | |
76 | + "description": "[WMTS]wmts_type"}, | |
77 | + {"name": "vendor", | |
78 | + "in": "formData", | |
79 | + "type": "string", | |
80 | + "description": "[WMTS]厂商"}, | |
81 | + {"name": "crs", | |
82 | + "in": "formData", | |
83 | + "type": "string", | |
84 | + "description": "[WMTS]坐标系"}, | |
85 | + {"name": "datasource", | |
86 | + "in": "formData", | |
87 | + "type": "string", | |
88 | + "description": "[WMTS]数据路径"}, | |
89 | + {"name": "layer_name", | |
90 | + "in": "formData", | |
91 | + "type": "string", | |
92 | + "description": "[WMTS]图层名"}, | |
93 | + {"name": "layer_alias", | |
94 | + "in": "formData", | |
95 | + "type": "string", | |
96 | + "description": "[WMTS]图层别名"}, | |
97 | + {"name": "layer_title", | |
98 | + "in": "formData", | |
99 | + "type": "string", | |
100 | + "description": "[WMTS]图层标题"}, | |
101 | + {"name": "layer_style", | |
102 | + "in": "formData", | |
103 | + "type": "string", | |
104 | + "description": "[WMTS,WMS]图层样式"}, | |
105 | + {"name": "layer_format", | |
106 | + "in": "formData", | |
107 | + "type": "string", | |
108 | + "description": "[WMTS]图层format"}, | |
109 | + {"name": "layer_extent", | |
110 | + "in": "formData", | |
111 | + "type": "string", | |
112 | + "description": "[WMTS]图层范围"}, | |
113 | + {"name": "layer_description", | |
114 | + "in": "formData", | |
115 | + "type": "string", | |
116 | + "description": "[WMTS]图层描述"}, | |
117 | + | |
118 | + # WMS参数 | |
119 | + {"name": "status", | |
120 | + "in": "formData", | |
121 | + "type": "string", | |
122 | + "description": "[WMS]status"}, | |
123 | + {"name": "username", | |
124 | + "in": "formData", | |
125 | + "type": "string", | |
126 | + "description": "[WMS]username"}, | |
127 | + {"name": "readonly", | |
128 | + "in": "formData", | |
129 | + "type": "string", | |
130 | + "description": "[WMS]readonly"}, | |
131 | + {"name": "sid", | |
132 | + "in": "formData", | |
133 | + "type": "string", | |
134 | + "description": "[WMS]sid"}, | |
135 | + {"name": "stype", | |
136 | + "in": "formData", | |
137 | + "type": "string", | |
138 | + "description": "[WMS]stype"}, | |
139 | + {"name": "ssupply", | |
140 | + "in": "formData", | |
141 | + "type": "string", | |
142 | + "description": "[WMS]ssupply"}, | |
143 | + {"name": "sctime", | |
144 | + "in": "formData", | |
145 | + "type": "string", | |
146 | + "description": "[WMS]sctime"}, | |
147 | + {"name": "company", | |
148 | + "in": "formData", | |
149 | + "type": "string", | |
150 | + "description": "[WMS]company"}, | |
151 | + {"name": "abstract", | |
152 | + "in": "formData", | |
153 | + "type": "string", | |
154 | + "description": "[WMS]abstract"}, | |
155 | + {"name": "thumbnail", | |
156 | + "in": "formData", | |
157 | + "type": "string", | |
158 | + "description": "[WMS]thumbnail"}, | |
37 | 159 | ], |
38 | 160 | "responses": { |
39 | 161 | 200: { | ... | ... |
... | ... | @@ -26,9 +26,14 @@ class Api(ApiTemplate): |
26 | 26 | name = self.para.get("name") |
27 | 27 | type = self.para.get("type") |
28 | 28 | |
29 | + catalog_guid = self.para.get("catalog_guid") | |
30 | + | |
29 | 31 | services = Service.query |
30 | 32 | if type: |
31 | 33 | services = services.filter_by(type=type) |
34 | + | |
35 | + if catalog_guid: | |
36 | + services = services.filter_by(catalog_guid=catalog_guid) | |
32 | 37 | # 并集 |
33 | 38 | if alias and name: |
34 | 39 | services = services.filter( |
... | ... | @@ -72,7 +77,12 @@ class Api(ApiTemplate): |
72 | 77 | {"name": "type", |
73 | 78 | "in": "formData", |
74 | 79 | "type": "string", |
75 | - "description": "服务类型"}, | |
80 | + "description": "服务类型", | |
81 | + "enum":["WMTS","TMS","WMS/WFS","ImageWMTS","ImageWMS"]}, | |
82 | + {"name": "catalog_guid", | |
83 | + "in": "formData", | |
84 | + "type": "string", | |
85 | + "description": "服务目录"}, | |
76 | 86 | ], |
77 | 87 | "responses": { |
78 | 88 | 200: { | ... | ... |
app/modules/service/service_state.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: 4N | |
3 | +#createtime: 2021/9/14 | |
4 | +#email: nheweijun@sina.com | |
5 | + | |
6 | + | |
7 | + | |
8 | + | |
9 | +from app.util.component.ApiTemplate import ApiTemplate | |
10 | +from app.models import Service,db | |
11 | +class Api(ApiTemplate): | |
12 | + api_name = "修改服务状态" | |
13 | + def process(self): | |
14 | + res = {} | |
15 | + try: | |
16 | + guid = self.para.get("guid") | |
17 | + state = int(self.para.get("state")) | |
18 | + Service.query.filter_by(guid=guid).update({"state":state}) | |
19 | + | |
20 | + | |
21 | + #更新缓存 | |
22 | + | |
23 | + | |
24 | + | |
25 | + db.session.commit() | |
26 | + except Exception as e: | |
27 | + raise e | |
28 | + return res | |
29 | + | |
30 | + | |
31 | + api_doc = { | |
32 | + "tags": ["服务接口"], | |
33 | + "parameters": [ | |
34 | + {"name": "guid", | |
35 | + "in": "formData", | |
36 | + "type": "string", | |
37 | + "description": "guid"}, | |
38 | + {"name": "stat", | |
39 | + "in": "formData", | |
40 | + "type": "int", | |
41 | + "description": "state"}, | |
42 | + ], | |
43 | + "responses": { | |
44 | + 200: { | |
45 | + "schema": { | |
46 | + "properties": { | |
47 | + } | |
48 | + } | |
49 | + } | |
50 | + } | |
51 | + } | |
\ No newline at end of file | ... | ... |
... | ... | @@ -6,8 +6,28 @@ |
6 | 6 | from flasgger import swag_from |
7 | 7 | from flask import Blueprint |
8 | 8 | from app.util import BlueprintApi |
9 | +from . import wms_register,wms_edit | |
9 | 10 | |
10 | 11 | class DataManager(BlueprintApi): |
11 | 12 | |
12 | 13 | bp = Blueprint("WMS", __name__, url_prefix="/API/Service/WMS") |
13 | - service_type = ["WMS"] | |
\ No newline at end of file | ||
14 | + service_type = ["WMS/WFS"] | |
15 | + | |
16 | + @staticmethod | |
17 | + @bp.route('/Register', methods=['POST']) | |
18 | + @swag_from(wms_register.Api.api_doc) | |
19 | + def api_wms_register(): | |
20 | + """ | |
21 | + 注册WMS | |
22 | + """ | |
23 | + return wms_register.Api().result | |
24 | + | |
25 | + | |
26 | + @staticmethod | |
27 | + @bp.route('/Edit', methods=['POST']) | |
28 | + @swag_from(wms_edit.Api.api_doc) | |
29 | + def api_wms_edit(): | |
30 | + """ | |
31 | + 修改WMS | |
32 | + """ | |
33 | + return wms_edit.Api().result | |
\ No newline at end of file | ... | ... |
... | ... | @@ -53,9 +53,76 @@ class Api(ApiTemplate): |
53 | 53 | return res |
54 | 54 | |
55 | 55 | api_doc = { |
56 | - "tags": ["影像接口"], | |
56 | + "tags": ["WMS接口"], | |
57 | 57 | "parameters": [ |
58 | 58 | |
59 | + {"name": "name", | |
60 | + "in": "formData", | |
61 | + "type": "string", | |
62 | + "required": "true", | |
63 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
64 | + {"name": "alias", | |
65 | + "in": "formData", | |
66 | + "type": "string", | |
67 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
68 | + {"name": "description", | |
69 | + "in": "formData", | |
70 | + "type": "string", | |
71 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
72 | + {"name": "catalog_guid", | |
73 | + "in": "formData", | |
74 | + "type": "string", | |
75 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
76 | + | |
77 | + | |
78 | + | |
79 | + {"name": "layer_style", | |
80 | + "in": "formData", | |
81 | + "type": "string", | |
82 | + "description": "[WMTS,WMS]图层样式"}, | |
83 | + | |
84 | + # WMS参数 | |
85 | + {"name": "status", | |
86 | + "in": "formData", | |
87 | + "type": "string", | |
88 | + "description": "[WMS]status"}, | |
89 | + {"name": "username", | |
90 | + "in": "formData", | |
91 | + "type": "string", | |
92 | + "description": "[WMS]username"}, | |
93 | + {"name": "readonly", | |
94 | + "in": "formData", | |
95 | + "type": "string", | |
96 | + "description": "[WMS]readonly"}, | |
97 | + {"name": "sid", | |
98 | + "in": "formData", | |
99 | + "type": "string", | |
100 | + "description": "[WMS]sid"}, | |
101 | + {"name": "stype", | |
102 | + "in": "formData", | |
103 | + "type": "string", | |
104 | + "description": "[WMS]stype"}, | |
105 | + {"name": "ssupply", | |
106 | + "in": "formData", | |
107 | + "type": "string", | |
108 | + "description": "[WMS]ssupply"}, | |
109 | + {"name": "sctime", | |
110 | + "in": "formData", | |
111 | + "type": "string", | |
112 | + "description": "[WMS]sctime"}, | |
113 | + {"name": "company", | |
114 | + "in": "formData", | |
115 | + "type": "string", | |
116 | + "description": "[WMS]company"}, | |
117 | + {"name": "abstract", | |
118 | + "in": "formData", | |
119 | + "type": "string", | |
120 | + "description": "[WMS]abstract"}, | |
121 | + {"name": "thumbnail", | |
122 | + "in": "formData", | |
123 | + "type": "string", | |
124 | + "description": "[WMS]thumbnail"}, | |
125 | + | |
59 | 126 | ], |
60 | 127 | "responses": { |
61 | 128 | 200: { | ... | ... |
... | ... | @@ -12,7 +12,7 @@ import datetime |
12 | 12 | import configure |
13 | 13 | class Api(ApiTemplate): |
14 | 14 | |
15 | - api_name = "注册WMTS服务" | |
15 | + api_name = "注册WMS服务" | |
16 | 16 | |
17 | 17 | def process(self): |
18 | 18 | # 返回结果 |
... | ... | @@ -74,7 +74,7 @@ class Api(ApiTemplate): |
74 | 74 | return res |
75 | 75 | |
76 | 76 | api_doc = { |
77 | - "tags": ["WMTS接口"], | |
77 | + "tags": ["WMS接口"], | |
78 | 78 | "parameters": [ |
79 | 79 | |
80 | 80 | {"name": "name", | ... | ... |
... | ... | @@ -7,16 +7,16 @@ |
7 | 7 | from flasgger import swag_from |
8 | 8 | from flask import Blueprint |
9 | 9 | from app.util import BlueprintApi |
10 | -from . import upload_oview | |
10 | +from . import upload_oview,wmts_register,wmts_edit | |
11 | 11 | |
12 | -import os | |
13 | -from flask import send_from_directory | |
14 | 12 | |
15 | 13 | |
16 | 14 | class DataManager(BlueprintApi): |
17 | 15 | |
18 | 16 | bp = Blueprint("WMTS", __name__, url_prefix="/API/Service/WMTS") |
19 | 17 | |
18 | + service_type = ["WMTS","MTS"] | |
19 | + | |
20 | 20 | @staticmethod |
21 | 21 | @bp.route('/UploadOverview', methods=['POST']) |
22 | 22 | @swag_from(upload_oview.Api.api_doc) |
... | ... | @@ -25,3 +25,23 @@ class DataManager(BlueprintApi): |
25 | 25 | 上传缩略图 |
26 | 26 | """ |
27 | 27 | return upload_oview.Api().result |
28 | + | |
29 | + | |
30 | + @staticmethod | |
31 | + @bp.route('/Register', methods=['POST']) | |
32 | + @swag_from(wmts_register.Api.api_doc) | |
33 | + def api_wmts_register(): | |
34 | + """ | |
35 | + 注册WMTS | |
36 | + """ | |
37 | + return wmts_register.Api().result | |
38 | + | |
39 | + @staticmethod | |
40 | + @bp.route('/Edit', methods=['POST']) | |
41 | + @swag_from(wmts_edit.Api.api_doc) | |
42 | + def api_wmts_edit(): | |
43 | + """ | |
44 | + 修改WMTS | |
45 | + """ | |
46 | + return wmts_edit.Api().result | |
47 | + | ... | ... |
... | ... | @@ -51,9 +51,84 @@ class Api(ApiTemplate): |
51 | 51 | return res |
52 | 52 | |
53 | 53 | api_doc = { |
54 | - "tags": ["影像接口"], | |
54 | + "tags": ["WMTS接口"], | |
55 | 55 | "parameters": [ |
56 | 56 | |
57 | + {"name": "name", | |
58 | + "in": "formData", | |
59 | + "type": "string", | |
60 | + "required": "true", | |
61 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
62 | + {"name": "alias", | |
63 | + "in": "formData", | |
64 | + "type": "string", | |
65 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
66 | + {"name": "description", | |
67 | + "in": "formData", | |
68 | + "type": "string", | |
69 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
70 | + | |
71 | + {"name": "catalog_guid", | |
72 | + "in": "formData", | |
73 | + "type": "string", | |
74 | + "description": "[WMS,WMTS,影像WMS,影像WMTS]"}, | |
75 | + | |
76 | + {"name": "scheme_guid", | |
77 | + "in": "formData", | |
78 | + "type": "string", | |
79 | + "description": "[WMTS,影像WMTS]切片方案"}, | |
80 | + | |
81 | + # WMTS参数 | |
82 | + {"name": "overview", | |
83 | + "in": "formData", | |
84 | + "type": "string", | |
85 | + "description": "[WMTS]缩略图"}, | |
86 | + {"name": "wmts_type", | |
87 | + "in": "formData", | |
88 | + "type": "string", | |
89 | + "description": "[WMTS]wmts_type"}, | |
90 | + {"name": "vendor", | |
91 | + "in": "formData", | |
92 | + "type": "string", | |
93 | + "description": "[WMTS]厂商"}, | |
94 | + {"name": "crs", | |
95 | + "in": "formData", | |
96 | + "type": "string", | |
97 | + "description": "[WMTS]坐标系"}, | |
98 | + {"name": "datasource", | |
99 | + "in": "formData", | |
100 | + "type": "string", | |
101 | + "description": "[WMTS]数据路径"}, | |
102 | + {"name": "layer_name", | |
103 | + "in": "formData", | |
104 | + "type": "string", | |
105 | + "description": "[WMTS]图层名"}, | |
106 | + {"name": "layer_alias", | |
107 | + "in": "formData", | |
108 | + "type": "string", | |
109 | + "description": "[WMTS]图层别名"}, | |
110 | + {"name": "layer_title", | |
111 | + "in": "formData", | |
112 | + "type": "string", | |
113 | + "description": "[WMTS]图层标题"}, | |
114 | + {"name": "layer_style", | |
115 | + "in": "formData", | |
116 | + "type": "string", | |
117 | + "description": "[WMTS,WMS]图层样式"}, | |
118 | + {"name": "layer_format", | |
119 | + "in": "formData", | |
120 | + "type": "string", | |
121 | + "description": "[WMTS]图层format"}, | |
122 | + {"name": "layer_extent", | |
123 | + "in": "formData", | |
124 | + "type": "string", | |
125 | + "description": "[WMTS]图层范围"}, | |
126 | + {"name": "layer_description", | |
127 | + "in": "formData", | |
128 | + "type": "string", | |
129 | + "description": "[WMTS]图层描述"}, | |
130 | + | |
131 | + | |
57 | 132 | ], |
58 | 133 | "responses": { |
59 | 134 | 200: { | ... | ... |
app/util/component/Geometry2Raster.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: 4N | |
3 | +#createtime: 2021/9/29 | |
4 | +#email: nheweijun@sina.com | |
5 | + | |
6 | +from osgeo.ogr import Layer,Geometry | |
7 | +from osgeo import gdal,ogr | |
8 | + | |
9 | + | |
10 | +class Geometry2Raster: | |
11 | + | |
12 | + | |
13 | + def __init__(self): | |
14 | + pass | |
15 | + | |
16 | + @classmethod | |
17 | + def convert(cls,geometry:Geometry,bbox, xy_res): | |
18 | + ''' | |
19 | + 根据Geometry和bbox将空间对象栅格化 | |
20 | + :param geometry: 空间对象 | |
21 | + :param bbox: 栅格化范围 | |
22 | + :param xy_res: 分辨率 | |
23 | + :return: | |
24 | + ''' | |
25 | + | |
26 | + #计算像素大小 | |
27 | + x_min,y_min,x_max, y_max = bbox | |
28 | + pixel_size = (x_max - x_min) / xy_res | |
29 | + #创建内存栅格对象 | |
30 | + target_ds = gdal.GetDriverByName('MEM').Create('', xy_res, xy_res, gdal.GDT_Byte) | |
31 | + target_ds.SetGeoTransform((x_min, pixel_size, 0, y_max, 0, -pixel_size)) | |
32 | + band = target_ds.GetRasterBand(1) | |
33 | + #创建内存图层对象,因为gdal只提供栅格化图层的方法 | |
34 | + layer_ds = ogr.GetDriverByName('Memory').CreateDataSource('') | |
35 | + mem_layer= layer_ds.CreateLayer("mem", geom_type=ogr.wkbUnknown) | |
36 | + feature_defn = mem_layer.GetLayerDefn() | |
37 | + feature = ogr.Feature(feature_defn) | |
38 | + feature.SetGeometry(geometry) | |
39 | + mem_layer.CreateFeature(feature) | |
40 | + #栅格化 | |
41 | + gdal.RasterizeLayer(target_ds, [1], mem_layer, burn_values=[1]) | |
42 | + data = band.ReadAsArray() | |
43 | + del target_ds | |
44 | + del layer_ds | |
45 | + return data | |
46 | + | |
47 | +if __name__ == '__main__': | |
48 | + | |
49 | + # Create ring | |
50 | + ring = ogr.Geometry(ogr.wkbLinearRing) | |
51 | + ring.AddPoint(111.62, 29) | |
52 | + ring.AddPoint(111.62, 29.03) | |
53 | + ring.AddPoint(111.727, 29.03) | |
54 | + ring.AddPoint(111.727, 29) | |
55 | + ring.AddPoint(111.62, 29) | |
56 | + | |
57 | + # Create polygon | |
58 | + poly = ogr.Geometry(ogr.wkbPolygon) | |
59 | + poly.AddGeometry(ring) | |
60 | + | |
61 | + poly.ExportToWkt() | |
62 | + | |
63 | + | ... | ... |
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | #author: 4N |
3 | 3 | #createtime: 2021/6/3 |
4 | 4 | #email: nheweijun@sina.com |
5 | -from osgeo import ogr | |
5 | +from osgeo import ogr,gdal | |
6 | 6 | from osgeo.ogr import Geometry |
7 | 7 | |
8 | 8 | class GeometryAdapter: |
... | ... | @@ -182,4 +182,36 @@ class GeometryAdapter: |
182 | 182 | g: Geometry = fea.geometry() |
183 | 183 | geom_type = g.GetGeometryType() |
184 | 184 | layer.ResetReading() |
185 | - return geom_type | |
\ No newline at end of file | ||
185 | + return geom_type | |
186 | + | |
187 | + @classmethod | |
188 | + def convert(cls, geometry: Geometry, bbox, xy_res): | |
189 | + ''' | |
190 | + 根据Geometry和bbox将空间对象栅格化 | |
191 | + :param geometry: 空间对象 | |
192 | + :param bbox: 栅格化范围 | |
193 | + :param xy_res: 分辨率 | |
194 | + :return: | |
195 | + ''' | |
196 | + | |
197 | + # 计算像素大小 | |
198 | + x_min, y_min, x_max, y_max = bbox | |
199 | + pixel_size = (x_max - x_min) / xy_res | |
200 | + # 创建内存栅格对象 | |
201 | + target_ds = gdal.GetDriverByName('MEM').Create('', xy_res, xy_res, gdal.GDT_Byte) | |
202 | + target_ds.SetGeoTransform((x_min, pixel_size, 0, y_max, 0, -pixel_size)) | |
203 | + band = target_ds.GetRasterBand(1) | |
204 | + # 创建内存图层对象,因为gdal只提供栅格化图层的方法 | |
205 | + layer_ds = ogr.GetDriverByName('Memory').CreateDataSource('') | |
206 | + mem_layer = layer_ds.CreateLayer("mem", geom_type=ogr.wkbUnknown) | |
207 | + feature_defn = mem_layer.GetLayerDefn() | |
208 | + feature = ogr.Feature(feature_defn) | |
209 | + feature.SetGeometry(geometry) | |
210 | + mem_layer.CreateFeature(feature) | |
211 | + # 栅格化 | |
212 | + gdal.RasterizeLayer(target_ds, [1], mem_layer, burn_values=[1]) | |
213 | + data = band.ReadAsArray() | |
214 | + del target_ds | |
215 | + del layer_ds | |
216 | + # Read as array | |
217 | + return data | |
\ No newline at end of file | ... | ... |
test/numpy_test.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: 4N | |
3 | +#createtime: 2021/9/29 | |
4 | +#email: nheweijun@sina.com | |
5 | + | |
6 | +def determine_level(xysize, origin_extent, extent, max_level): | |
7 | + ''' | |
8 | + 根据范围判断调用金字塔的哪一层 | |
9 | + :param xysize: | |
10 | + :param origin_extent: | |
11 | + :param extent: | |
12 | + :param max_level: | |
13 | + :return: | |
14 | + ''' | |
15 | + x = xysize[0] | |
16 | + y = xysize[1] | |
17 | + level = -1 | |
18 | + pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / ( | |
19 | + (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1]))) | |
20 | + while pixel > 100000 and level < max_level - 1: | |
21 | + level += 1 | |
22 | + x = x / 2 | |
23 | + y = y / 2 | |
24 | + pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / ( | |
25 | + (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1]))) | |
26 | + return level | |
27 | + | |
28 | +import math | |
29 | +def determine_level2(xysize, origin_extent, extent, max_level): | |
30 | + ''' | |
31 | + 根据范围判断调用金字塔的哪一层 | |
32 | + :param xysize: | |
33 | + :param origin_extent: | |
34 | + :param extent: | |
35 | + :param max_level: | |
36 | + :return: | |
37 | + ''' | |
38 | + x = xysize[0] | |
39 | + y = xysize[1] | |
40 | + | |
41 | + level_up = round (math.sqrt( round (math.sqrt((x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / ( | |
42 | + (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1])))) / 100000)))) | |
43 | + | |
44 | + | |
45 | + return level_up - 1 if level_up < max_level else max_level - 1 | |
46 | + | |
47 | +import time | |
48 | +t1 = time.time() | |
49 | + | |
50 | +print(determine_level2([108488,90777],[111.639350712, 28.9170588759, 111.751508603, 29.032941696], | |
51 | + [111.739350712, 29.0070588759, 111.751508603, 29.032941696],9)) | |
52 | +print(time.time()-t1) | |
53 | +t1 = time.time() | |
54 | + | |
55 | +print(determine_level([108488,90777],[111.639350712, 28.9170588759, 111.751508603, 29.032941696], | |
56 | + [111.739350712, 29.0070588759, 111.751508603, 29.032941696],9)) | |
57 | + | |
58 | +print(time.time()-t1) | |
\ No newline at end of file | ... | ... |
test/shp2raster.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: 4N | |
3 | +#createtime: 2021/9/28 | |
4 | +#email: nheweijun@sina.com | |
5 | + | |
6 | + | |
7 | +from osgeo import gdal,ogr | |
8 | +from osgeo.ogr import Layer,Feature | |
9 | + | |
10 | +vector_fn = r'E:\Data\广东边界\gdsample.shp' | |
11 | + | |
12 | +# Define pixel_size and NoData value of new raster | |
13 | +pixel_size = 0.1 | |
14 | +NoData_value = 255 | |
15 | + | |
16 | +# Open the data source and read in the extent | |
17 | +source_ds = ogr.Open(vector_fn) | |
18 | +source_layer:Layer = source_ds.GetLayer() | |
19 | +source_srs = source_layer.GetSpatialRef() | |
20 | +x_min, x_max, y_min, y_max = source_layer.GetExtent() | |
21 | + | |
22 | +# Create the destination data source | |
23 | +x_res = int((x_max - (x_min-2)) / pixel_size) | |
24 | +y_res = int((y_max - y_min) / pixel_size) | |
25 | +target_ds = gdal.GetDriverByName('GTiff').Create('t.tiff', x_res, y_res, gdal.GDT_Byte) | |
26 | +target_ds.SetGeoTransform((x_min-2, pixel_size, 0, y_max, 0, -pixel_size)) | |
27 | +band = target_ds.GetRasterBand(1) | |
28 | +band.SetNoDataValue(NoData_value) | |
29 | + | |
30 | +# Rasterize | |
31 | +kk:Feature = source_layer.GetFeature(0) | |
32 | + | |
33 | +layer_ds = ogr.GetDriverByName('Memory').CreateDataSource('') | |
34 | +outLayer = layer_ds.CreateLayer("mem",geom_type=ogr.wkbUnknown) | |
35 | +featureDefn = outLayer.GetLayerDefn() | |
36 | +outFeature = ogr.Feature(featureDefn) | |
37 | +outFeature.SetGeometry(kk.geometry()) | |
38 | +outLayer.CreateFeature(outFeature) | |
39 | + | |
40 | +gdal.RasterizeLayer(target_ds, [1], outLayer, burn_values=[1]) | |
41 | + | |
42 | + | |
43 | +# Read as array | |
44 | +array = band.ReadAsArray() | |
45 | +print(array) | |
\ No newline at end of file | ... | ... |
test/t.tiff
0 → 100644
不能预览此文件类型
请
注册
或
登录
后发表评论