提交 25ceb357b6f4dbec1ac5b23f7a2414f61be7093d

作者 nheweijun
1 个父辈 006d265f

架构重新设计之前

... ... @@ -3,7 +3,7 @@ import base64
3 3 import os
4 4 from flask_sqlalchemy import SQLAlchemy,Model
5 5 import importlib
6   -from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time,Float
  6 +from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time,Float,Binary
7 7 from sqlalchemy.orm import relationship
8 8 import base64
9 9 from pyDes import *
... ... @@ -198,3 +198,22 @@ class InsertingLayerName(db.Model):
198 198 task_guid = Column(String(256))
199 199 name = Column(String(256))
200 200
  201 +
  202 +# class Service(db.Model):
  203 +# '''
  204 +# '''
  205 +# __tablename__ = 'dmdms_service'
  206 +# guid = Column(String(256), primary_key=True)
  207 +# name=Column(String(256))
  208 +# alias = Column(String(256))
  209 +# #服务状态
  210 +# state= Column(Integer)
  211 +# create_time = Column(DateTime)
  212 +# update_time = Column(DateTime)
  213 +# #服务描述
  214 +# description = Column(Text)
  215 +# #服务节点
  216 +# node = Column(Integer)
  217 +# #服务缩略图
  218 +# overview = Column(Binary)
  219 +
... ...
... ... @@ -146,34 +146,35 @@ class Api(ApiTemplate):
146 146 table_guid = uuid.uuid1().__str__()
147 147
148 148 geom_type = GeometryAdapter.get_geometry_type(layer)
  149 +
  150 +
  151 + table = Table(guid=table_guid,
  152 + database_guid=database.guid,
  153 + # alias=layer.GetName(),
  154 + name=layer.GetName(), create_time=this_time, update_time=this_time,
  155 + table_type=GeometryAdapter.get_table_type(geom_type),
  156 + extent=extent,
  157 + feature_count=feature_count
  158 + )
  159 +
  160 + db.session.add(table)
  161 + tables.append(table)
  162 +
  163 + feature_defn: FeatureDefn = layer.GetLayerDefn()
  164 +
  165 + for i in range(feature_defn.GetFieldCount()):
  166 + field_defn: FieldDefn = feature_defn.GetFieldDefn(i)
  167 + field_name = field_defn.GetName().lower()
  168 + field_alias = field_name if field_defn.GetAlternativeName() is None or field_defn.GetAlternativeName().__eq__(
  169 + "") else field_defn.GetAlternativeName()
  170 + column = Columns(guid=uuid.uuid1().__str__(), table_guid=table_guid,
  171 + name=field_name, alias=field_alias, create_time=this_time, update_time=this_time)
  172 + db.session.add(column)
  173 +
  174 + spatial_table_name.append(layer.GetName())
149 175 except:
150 176 StructurePrint.print("表{}注册失败!".format(l_name), "warn")
151 177 continue
152   -
153   - table = Table(guid=table_guid,
154   - database_guid=database.guid,
155   - # alias=layer.GetName(),
156   - name=layer.GetName(), create_time=this_time, update_time=this_time,
157   - table_type=GeometryAdapter.get_table_type(geom_type),
158   - extent=extent,
159   - feature_count=feature_count
160   - )
161   -
162   - db.session.add(table)
163   - tables.append(table)
164   -
165   - feature_defn: FeatureDefn = layer.GetLayerDefn()
166   -
167   - for i in range(feature_defn.GetFieldCount()):
168   - field_defn: FieldDefn = feature_defn.GetFieldDefn(i)
169   - field_name = field_defn.GetName().lower()
170   - field_alias = field_name if field_defn.GetAlternativeName() is None or field_defn.GetAlternativeName().__eq__(
171   - "") else field_defn.GetAlternativeName()
172   - column = Columns(guid=uuid.uuid1().__str__(), table_guid=table_guid,
173   - name=field_name, alias=field_alias, create_time=this_time, update_time=this_time)
174   - db.session.add(column)
175   -
176   - spatial_table_name.append(layer.GetName())
177 178 return spatial_table_name,tables
178 179
179 180
... ...
... ... @@ -24,7 +24,7 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help':
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(' string getData(string path, queryRange, originRange, bands)')
  27 + print(' string getData(string path, queryRange, originRange, bands, i32 width, i32 height)')
28 28 print(' string getInfo(string path)')
29 29 print(' bool buildOverview(string path)')
30 30 print(' string getImageList(string path)')
... ... @@ -108,10 +108,10 @@ client = ImageDataService.Client(protocol)
108 108 transport.open()
109 109
110 110 if cmd == 'getData':
111   - if len(args) != 4:
112   - print('getData requires 4 args')
  111 + if len(args) != 6:
  112 + print('getData requires 6 args')
113 113 sys.exit(1)
114   - pp.pprint(client.getData(args[0], eval(args[1]), eval(args[2]), eval(args[3]),))
  114 + pp.pprint(client.getData(args[0], eval(args[1]), eval(args[2]), eval(args[3]), eval(args[4]), eval(args[5]),))
115 115
116 116 elif cmd == 'getInfo':
117 117 if len(args) != 1:
... ...
... ... @@ -19,13 +19,15 @@ all_structs = []
19 19
20 20
21 21 class Iface(object):
22   - def getData(self, path, queryRange, originRange, bands):
  22 + def getData(self, path, queryRange, originRange, bands, width, height):
23 23 """
24 24 Parameters:
25 25 - path
26 26 - queryRange
27 27 - originRange
28 28 - bands
  29 + - width
  30 + - height
29 31
30 32 """
31 33 pass
... ... @@ -62,25 +64,29 @@ class Client(Iface):
62 64 self._oprot = oprot
63 65 self._seqid = 0
64 66
65   - def getData(self, path, queryRange, originRange, bands):
  67 + def getData(self, path, queryRange, originRange, bands, width, height):
66 68 """
67 69 Parameters:
68 70 - path
69 71 - queryRange
70 72 - originRange
71 73 - bands
  74 + - width
  75 + - height
72 76
73 77 """
74   - self.send_getData(path, queryRange, originRange, bands)
  78 + self.send_getData(path, queryRange, originRange, bands, width, height)
75 79 return self.recv_getData()
76 80
77   - def send_getData(self, path, queryRange, originRange, bands):
  81 + def send_getData(self, path, queryRange, originRange, bands, width, height):
78 82 self._oprot.writeMessageBegin('getData', TMessageType.CALL, self._seqid)
79 83 args = getData_args()
80 84 args.path = path
81 85 args.queryRange = queryRange
82 86 args.originRange = originRange
83 87 args.bands = bands
  88 + args.width = width
  89 + args.height = height
84 90 args.write(self._oprot)
85 91 self._oprot.writeMessageEnd()
86 92 self._oprot.trans.flush()
... ... @@ -233,7 +239,7 @@ class Processor(Iface, TProcessor):
233 239 iprot.readMessageEnd()
234 240 result = getData_result()
235 241 try:
236   - result.success = self._handler.getData(args.path, args.queryRange, args.originRange, args.bands)
  242 + result.success = self._handler.getData(args.path, args.queryRange, args.originRange, args.bands, args.width, args.height)
237 243 msg_type = TMessageType.REPLY
238 244 except TTransport.TTransportException:
239 245 raise
... ... @@ -329,15 +335,19 @@ class getData_args(object):
329 335 - queryRange
330 336 - originRange
331 337 - bands
  338 + - width
  339 + - height
332 340
333 341 """
334 342
335 343
336   - def __init__(self, path=None, queryRange=None, originRange=None, bands=None,):
  344 + def __init__(self, path=None, queryRange=None, originRange=None, bands=None, width=None, height=None,):
337 345 self.path = path
338 346 self.queryRange = queryRange
339 347 self.originRange = originRange
340 348 self.bands = bands
  349 + self.width = width
  350 + self.height = height
341 351
342 352 def read(self, iprot):
343 353 if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None:
... ... @@ -383,6 +393,16 @@ class getData_args(object):
383 393 iprot.readListEnd()
384 394 else:
385 395 iprot.skip(ftype)
  396 + elif fid == 5:
  397 + if ftype == TType.I32:
  398 + self.width = iprot.readI32()
  399 + else:
  400 + iprot.skip(ftype)
  401 + elif fid == 6:
  402 + if ftype == TType.I32:
  403 + self.height = iprot.readI32()
  404 + else:
  405 + iprot.skip(ftype)
386 406 else:
387 407 iprot.skip(ftype)
388 408 iprot.readFieldEnd()
... ... @@ -418,6 +438,14 @@ class getData_args(object):
418 438 oprot.writeI32(iter20)
419 439 oprot.writeListEnd()
420 440 oprot.writeFieldEnd()
  441 + if self.width is not None:
  442 + oprot.writeFieldBegin('width', TType.I32, 5)
  443 + oprot.writeI32(self.width)
  444 + oprot.writeFieldEnd()
  445 + if self.height is not None:
  446 + oprot.writeFieldBegin('height', TType.I32, 6)
  447 + oprot.writeI32(self.height)
  448 + oprot.writeFieldEnd()
421 449 oprot.writeFieldStop()
422 450 oprot.writeStructEnd()
423 451
... ... @@ -441,6 +469,8 @@ getData_args.thrift_spec = (
441 469 (2, TType.LIST, 'queryRange', (TType.DOUBLE, None, False), None, ), # 2
442 470 (3, TType.LIST, 'originRange', (TType.DOUBLE, None, False), None, ), # 3
443 471 (4, TType.LIST, 'bands', (TType.I32, None, False), None, ), # 4
  472 + (5, TType.I32, 'width', None, None, ), # 5
  473 + (6, TType.I32, 'height', None, None, ), # 6
444 474 )
445 475
446 476
... ...
... ... @@ -15,7 +15,7 @@ from . import data_list
15 15 from . import capabilities
16 16 from . import image_list
17 17 from . import image_tile
18   -
  18 +from . import image_wms
19 19
20 20 class DataManager(BlueprintApi):
21 21
... ... @@ -101,4 +101,15 @@ class DataManager(BlueprintApi):
101 101 """
102 102 切片服务
103 103 """
104   - return image_tile.Api("1",1,1,1).result
\ No newline at end of file
  104 + return image_tile.Api("1",1,1,1).result
  105 +
  106 +
  107 +
  108 + @staticmethod
  109 + @bp.route('/WMS', methods=['GET','POST'])
  110 + @swag_from(image_wms.Api.api_doc)
  111 + def image_wms():
  112 + """
  113 + WMS服务
  114 + """
  115 + return image_wms.Api().result
\ No newline at end of file
... ...
... ... @@ -12,7 +12,7 @@ import json
12 12 from app.modules.image.ImageDataService import ImageDataService
13 13 from app.util.component.FileProcess import FileProcess
14 14 import datetime
15   -
  15 +from app.util.component.ThriftConnect import ThriftConnect
16 16 import os
17 17 class Api(ApiTemplate):
18 18
... ... @@ -56,20 +56,14 @@ class Api(ApiTemplate):
56 56 elif os.path.isdir(file_path):
57 57 file_info["type"] = "dir"
58 58 data_list.append(file_info)
  59 +
59 60 data_list_sorted = sorted(data_list, key=lambda x: x["name"])
60 61 res["data"] = data_list_sorted
61 62
62 63 else:
63   - host = data_server.split(":")[0]
64   - port = int(data_server.split(":")[1])
65   -
66   - transport = TSocket.TSocket(host, port)
67   - transport = TTransport.TBufferedTransport(transport)
68   - protocol = TBinaryProtocol.TBinaryProtocol(transport)
69   - client = ImageDataService.Client(protocol)
70   - transport.open()
71   - info= json.loads(client.getImageList(path))
72   - transport.close()
  64 + thrift_connect = ThriftConnect(data_server)
  65 + info= json.loads(thrift_connect.client.getImageList(path))
  66 + thrift_connect.close()
73 67 res["data"] = info
74 68
75 69 res["result"] = True
... ...
  1 +# coding=utf-8
  2 +#author: 4N
  3 +#createtime: 2021/7/19
  4 +#email: nheweijun@sina.com
  5 +
  6 +from app.util.component.ApiTemplate import ApiTemplate
  7 +from app.models import db
  8 +from .models import Image
  9 +class Api(ApiTemplate):
  10 +
  11 + api_name = "删除影像数据"
  12 +
  13 + def process(self):
  14 +
  15 + res = {}
  16 +
  17 + try:
  18 + guid = self.para.get("guid")
  19 + image = Image.query.filter_by(guid=guid).one_or_none()
  20 + db.session.commit()
  21 + # res["data"] = guid
  22 + res["result"] = True
  23 +
  24 + except Exception as e:
  25 + raise e
  26 +
  27 + return res
  28 +
  29 + api_doc = {
  30 + "tags": ["影像接口"],
  31 + "parameters": [
  32 + {"name": "guid",
  33 + "in": "formData",
  34 + "type": "string",
  35 + "description": "data_server"}
  36 + ],
  37 + "responses": {
  38 + 200: {
  39 + "schema": {
  40 + "properties": {
  41 + }
  42 + }
  43 + }
  44 + }
  45 + }
  46 +
  47 +
... ...
  1 +# coding=utf-8
  2 +#author: 4N
  3 +#createtime: 2021/9/8
  4 +#email: nheweijun@sina.com
... ...
... ... @@ -8,7 +8,7 @@ from app.util.component.ApiTemplate import ApiTemplate
8 8 from app.util.component.ModelVisitor import ModelVisitor
9 9
10 10 from app.modules.image.models import Image
11   -
  11 +from sqlalchemy import or_,and_
12 12 class Api(ApiTemplate):
13 13
14 14 api_name = "影像数据List"
... ... @@ -23,9 +23,19 @@ class Api(ApiTemplate):
23 23
24 24 alias = self.para.get("alias")
25 25 name = self.para.get("name")
  26 + images = Image.query
  27 +
  28 + # 并集
  29 + if alias and name:
  30 + images = images.filter(or_(Image.alias.like("%" + alias + "%") , Image.name.like("%" + name + "%")))
  31 + else:
  32 + if alias:
  33 + images = images.filter(Image.alias.like("%" + alias + "%"))
  34 + if name:
  35 + images = images.filter(Image.name.like("%" + name + "%"))
26 36
  37 + images = images.limit(page_size).offset(page_index).all()
27 38
28   - images = Image.query.all()
29 39 res["data"] = ModelVisitor.objects_to_jsonarray(images)
30 40 res["result"] = True
31 41 except Exception as e:
... ...
... ... @@ -3,106 +3,138 @@
3 3 #createtime: 2021/7/19
4 4 #email: nheweijun@sina.com
5 5
6   -from osgeo.ogr import *
  6 +
7 7 from osgeo import gdal,ogr,osr
8 8 from osgeo.gdal import Dataset,Band
9 9 from app.util.component.ApiTemplate import ApiTemplate
  10 +from app.util.component.ThriftConnect import ThriftConnect
10 11
11   -
12   -from thrift.transport import TSocket
13   -from thrift.transport import TTransport
14   -from thrift.protocol import TBinaryProtocol
15   -import numpy
16   -import cv2
17 12 import json
18 13 from .models import Image
19   -from app.modules.image.ImageDataService import ImageDataService
  14 +import datetime
20 15 from app.models import db
21 16 import uuid
22 17 import os
  18 +import math
23 19 class Api(ApiTemplate):
24 20
25 21 api_name = "注册影像数据"
26 22
27 23 def process(self):
28 24
29   -
30   - # 返回结果
  25 + #可以注册一个目录
  26 + #返回结果
31 27 res = {}
32 28
33 29 try:
34 30 data_server = self.para.get("data_server")
  31 + paths = json.loads(self.para.get("paths"))
35 32
36   - path = self.para.get("path")
  33 + #注册某影像
  34 + infos = []
  35 + if data_server.__eq__("本地服务器"):
37 36
  37 + image_paths = list(self.recur_paths_local(paths))
38 38
39   - if data_server.__eq__("本地服务器"):
40   - host = data_server
41   - port = 0
  39 + for image_info in image_paths:
42 40
43   - image: Dataset = gdal.Open(path, 0)
44   - geo = image.GetGeoTransform()
  41 + image: Dataset = gdal.Open(image_info["path"], 0)
  42 + geo = image.GetGeoTransform()
45 43
46   - origin = osr.SpatialReference()
47   - origin.ImportFromWkt(image.GetProjection())
48   - band_count = image.RasterCount
49   - band: Band = image.GetRasterBand(1)
50   - count = band.GetOverviewCount()
51   - nodatavalue = band.GetNoDataValue()
52   - left_top = (geo[0], geo[3])
  44 + origin = osr.SpatialReference()
  45 + origin.ImportFromWkt(image.GetProjection())
53 46
54   - right_buttom = (geo[0] + geo[1] * image.RasterXSize, geo[3] + geo[5] * image.RasterYSize)
55   - origin_extent = [left_top[0], right_buttom[0], right_buttom[1], left_top[1]]
  47 + authority_code = origin.GetAuthorityCode()
  48 + band_count = image.RasterCount
  49 + band: Band = image.GetRasterBand(1)
  50 + count = band.GetOverviewCount()
  51 + nodatavalue = band.GetNoDataValue()
  52 + left_top = (geo[0], geo[3])
56 53
57   - info = {"band_count": band_count, "overview_count": count,
58   - "xy_size": [image.RasterXSize, image.RasterYSize]
59   - , "origin_extent": origin_extent, "null_value": nodatavalue}
  54 + right_buttom = (geo[0] + geo[1] * image.RasterXSize, geo[3] + geo[5] * image.RasterYSize)
  55 + origin_extent = [left_top[0], right_buttom[0], right_buttom[1], left_top[1]]
60 56
61   - del image
  57 + target = origin.CloneGeogCS()
  58 + tran = osr.CoordinateTransformation(origin, target)
  59 +
  60 + geo_left_top = tran.TransformPoint(geo[0], geo[3])
  61 + geo_right_buttom = tran.TransformPoint(geo[0] + geo[1] * image.RasterXSize,
  62 + geo[3] + geo[5] * image.RasterYSize)
  63 +
  64 + geo_origin_extent = [geo_left_top[1], geo_right_buttom[0], geo_right_buttom[1], geo_left_top[0]]
  65 +
  66 + info = {"band_count": band_count,
  67 + "overview_count": count,
  68 + "path":image_info["path"],
  69 + "xy_size": [image.RasterXSize, image.RasterYSize],
  70 + "origin_extent": origin_extent,
  71 + "geo_origin_extent": geo_origin_extent,
  72 + "null_value": nodatavalue,
  73 + "size":os.path.getsize(image_info["path"]),
  74 + "sr_wkt": image.GetProjection(),
  75 + "epsg": authority_code,
  76 + "sr_proj4": origin.ExportToProj4(),
  77 + "cell_x_size": geo[1],
  78 + "cell_y_size": geo[5]
  79 + }
  80 +
  81 + infos.append(info)
  82 + del image
62 83
63 84 else:
64   - host = data_server.split(":")[0]
65   - port = int(data_server.split(":")[1])
66   -
67   - transport = TSocket.TSocket(host, port)
68   - transport = TTransport.TBufferedTransport(transport)
69   - protocol = TBinaryProtocol.TBinaryProtocol(transport)
70   - client = ImageDataService.Client(protocol)
71   - transport.open()
72   - info= json.loads(client.getInfo(path))
73   - transport.close()
74   -
75   - # 影像空间范围
76   - if not info["origin_extent"]:
77   - if not self.para.get("extent"):
78   - res["result"] = False
79   - res["msg"] = "数据解析范围失败,请手动输入范围"
80   - return res
81   - else :
82   - origin_extent=json.loads(self.para.get("extent"))
83   - else:
84   - origin_extent = info["origin_extent"]
85   -
86   -
87   - guid = uuid.uuid1().__str__()
88   -
89   - image = Image(guid= guid,
90   - overview=info["overview_count"],
91   - raster_x_size=info["xy_size"][0],
92   - raster_y_size=info["xy_size"][1],
93   - name=os.path.basename(path),
94   - alias=self.para.get("alias"),
95   - extent=json.dumps(origin_extent),
96   - null_value=info["null_value"],
97   - host=host,
98   - port=port,
99   - # path=os.path.normpath(path)
100   - path = path
101   - )
102   -
103   - db.session.add(image)
  85 + thrift_connect = ThriftConnect(data_server)
  86 + image_paths = list(self.recur_paths_remote(paths,thrift_connect.client))
  87 + for image_info in image_paths:
  88 + infos.append(json.loads(thrift_connect.client.getInfo(image_info["path"])))
  89 + thrift_connect.close()
  90 +
  91 + this_time = datetime.datetime.now()
  92 + for info in infos:
  93 +
  94 + # 影像空间范围
  95 + # if not info["origin_extent"]:
  96 + # if not self.para.get("extent"):
  97 + # res["result"] = False
  98 + # res["msg"] = "数据解析范围失败,请手动输入范围"
  99 + # return res
  100 + # else :
  101 + # origin_extent=json.loads(self.para.get("extent"))
  102 + # else:
  103 + # origin_extent = info["origin_extent"]
  104 +
  105 +
  106 +
  107 +
  108 + exist_image = Image.query.filter_by(path=os.path.normpath(info.get("path")),
  109 + size=info.get("size")).one_or_none()
  110 + if exist_image:
  111 + if exist_image.server.__contains__(data_server):
  112 + pass
  113 + else:
  114 + exist_image.update({"server":"{},".format(data_server)})
  115 + else:
  116 + image = Image(guid= uuid.uuid1().__str__(),
  117 + overview_count=info.get("overview_count"),
  118 + raster_x_size=info["xy_size"][0],
  119 + raster_y_size=info["xy_size"][1],
  120 + cell_x_size = info.get("cell_x_size"),
  121 + cell_y_size = abs(info.get("cell_y_size")),
  122 + name=os.path.basename(info.get("path")),
  123 + origin_extent=json.dumps(info["origin_extent"]),
  124 + geo_origin_extent = json.dumps(info["geo_origin_extent"]),
  125 + null_value=info.get("null_value"),
  126 + server=data_server,
  127 + path = os.path.normpath(info.get("path")),
  128 + size=info.get("size"),
  129 + epsg= info.get("epsg"),
  130 + sr_wkt = info.get("sr_wkt"),
  131 + sr_proj4= info.get("sr_proj4"),
  132 + band_count=info.get("band_count"),
  133 + create_time=this_time
  134 + )
  135 + db.session.add(image)
104 136 db.session.commit()
105   - res["data"] = guid
  137 + # res["data"] = guid
106 138 res["result"] = True
107 139
108 140 except Exception as e:
... ... @@ -110,7 +142,35 @@ class Api(ApiTemplate):
110 142
111 143 return res
112 144
113   -
  145 + def recur_paths_local(self,paths):
  146 + for path in paths:
  147 + if path["type"].__eq__("dir"):
  148 + data_list: list = []
  149 + for f in os.listdir(path["path"]):
  150 + file_path = os.path.normpath(os.path.join(path["path"], f))
  151 + file_info = {"name": f, "path": file_path}
  152 + if file_path.lower().endswith("tiff") or file_path.lower().endswith("tif"):
  153 + file_info["type"] = "tif"
  154 + data_list.append(file_info)
  155 + elif file_path.lower().endswith("img"):
  156 + file_info["type"] = "img"
  157 + data_list.append(file_info)
  158 + elif os.path.isdir(file_path):
  159 + file_info["type"] = "dir"
  160 + data_list.append(file_info)
  161 + for p in self.recur_paths_local(data_list):
  162 + yield p
  163 + else:
  164 + yield path
  165 +
  166 + def recur_paths_remote(self,paths,client):
  167 + for path in paths:
  168 + if path["type"].__eq__("dir"):
  169 + path_list = json.loads(client.getImageList(path["path"]))
  170 + for p in self.recur_paths_remote(path_list,client):
  171 + yield p
  172 + else:
  173 + yield path
114 174 api_doc = {
115 175 "tags": ["影像接口"],
116 176 "parameters": [
... ... @@ -118,10 +178,10 @@ class Api(ApiTemplate):
118 178 "in": "formData",
119 179 "type": "string",
120 180 "description": "data_server"},
121   - {"name": "path",
  181 + {"name": "paths",
122 182 "in": "formData",
123 183 "type": "string",
124   - "description": "path"}
  184 + "description": "paths"}
125 185 ],
126 186 "responses": {
127 187 200: {
... ...
... ... @@ -7,7 +7,7 @@
7 7 from app.util.component.ApiTemplate import ApiTemplate
8 8 from app.util.component.ModelVisitor import ModelVisitor
9 9 from app.modules.image.models import ImageService
10   -
  10 +from sqlalchemy import or_
11 11
12 12 class Api(ApiTemplate):
13 13
... ... @@ -32,8 +32,17 @@ class Api(ApiTemplate):
32 32 alias = self.para.get("alias")
33 33 name = self.para.get("name")
34 34
35   -
36   - image_services = ImageService.query.all()
  35 + image_services = ImageService.query
  36 + # 并集
  37 + if alias and name:
  38 + image_services = image_services.filter(or_(ImageService.alias.like("%" + alias + "%") , ImageService.name.like("%" + name + "%")))
  39 + else:
  40 + if alias:
  41 + image_services = image_services.filter(ImageService.alias.like("%" + alias + "%"))
  42 + if name:
  43 + image_services = image_services.filter(ImageService.name.like("%" + name + "%"))
  44 +
  45 + image_services = image_services.limit(page_size).offset(page_index).all()
37 46
38 47 res["data"] = ModelVisitor.objects_to_jsonarray(image_services)
39 48 res["result"] = True
... ...
... ... @@ -11,6 +11,7 @@ from app.util.component.SliceScheme import SliceScheme
11 11 from app.util.component.FileProcess import FileProcess
12 12 import os
13 13 import json
  14 +import datetime
14 15 class Api(ApiTemplate):
15 16
16 17 api_name = "注册影像服务"
... ... @@ -32,13 +33,14 @@ class Api(ApiTemplate):
32 33 dir_path, store_file = FileProcess.save(parent)
33 34 scheme = SliceScheme(store_file).parameter
34 35
35   - service = ImageService(guid=service_guid, name=name, slice_scheme=json.dumps(scheme))
  36 + service = ImageService(guid=service_guid, name=name, slice_scheme=json.dumps(scheme),
  37 + create_time=datetime.datetime.now())
36 38 service_exetent = []
37 39
38 40 for g in guids:
39 41 image = Image.query.filter_by(guid=g).one_or_none()
40 42 if image:
41   - image_extent = json.loads(image.extent)
  43 + image_extent = json.loads(image.origin_extent)
42 44 if not service_exetent:
43 45 service_exetent = image_extent
44 46 else:
... ... @@ -50,6 +52,9 @@ class Api(ApiTemplate):
50 52 service.extent = json.dumps(service_exetent)
51 53 db.session.add(service)
52 54 db.session.commit()
  55 +
  56 + #获得overview
  57 +
53 58 res["data"] = service_guid
54 59 res["result"] = True
55 60 except Exception as e:
... ...
  1 +# coding=utf-8
  2 +#author: 4N
  3 +#createtime: 2021/9/8
  4 +#email: nheweijun@sina.com
... ...
... ... @@ -29,13 +29,11 @@ import json
29 29 from kazoo.client import KazooClient
30 30 from app import GLOBAL_DIC
31 31 from threading import Thread
32   -from thrift.transport import TSocket
33   -from thrift.transport import TTransport
34   -from thrift.protocol import TBinaryProtocol
35   -from .ImageDataService import ImageDataService
  32 +
  33 +from app.util.component.ThriftConnect import ThriftConnect
36 34 from flask import current_app
37 35 import gzip
38   -
  36 +import random
39 37 class Api(ApiTemplate):
40 38
41 39 api_name = "切片"
... ... @@ -90,47 +88,76 @@ class Api(ApiTemplate):
90 88 slice_para = json.loads(image_service.slice_scheme)
91 89 extent = SliceScheme.get_polygon(slice_para, self.level, self.row, self.col)
92 90
93   - # 结果矩阵
94   - empty_list = [numpy.zeros((256, 256), dtype=int) + 65536,
95   - numpy.zeros((256, 256), dtype=int) + 65536,
96   - numpy.zeros((256, 256), dtype=int) + 65536]
  91 + height, width = 256,256
97 92
98 93 # 多线程获取分布式数据
  94 + if abs(extent[0])>180:
  95 + intersect_image = [im for im in images if self.determin_intersect(json.loads(im.origin_extent),extent)]
  96 + else:
  97 + intersect_image = [im for im in images if self.determin_intersect(json.loads(im.geo_origin_extent), extent)]
  98 +
  99 +
  100 + if len(intersect_image) > 1:
  101 +
  102 + # 结果矩阵
  103 + empty_list = [numpy.zeros((height, width), dtype=int) + 65536,
  104 + numpy.zeros((height, width), dtype=int) + 65536,
  105 + numpy.zeros((height, width), dtype=int) + 65536]
  106 +
  107 + pixel_array = numpy.zeros((height, width, 3), dtype=int)
  108 + thread_list = []
  109 +
  110 + for image in intersect_image:
  111 + # 该影像的服务器,随机选取一个
  112 + image_servers = image.server.split(",")
  113 + indx = int(random.random() * len(image_servers))
  114 + image_server = image_servers[indx]
  115 +
  116 + thread: MyThread = MyThread(self.get_data,
  117 + args=(zoo, image_server, image, extent, bands, height, width))
  118 + thread.start()
  119 + thread_list.append(thread)
  120 +
  121 + for thread in thread_list:
  122 + thread.join()
  123 + data = thread.get_result()
  124 +
  125 + # 掩膜在中央接口生成,合图
  126 + mask = numpy.zeros((height, width), dtype=int)
  127 + mask2 = numpy.zeros((height, width), dtype=int)
  128 + jizhun = data[:, :, 0]
  129 + mask[jizhun == 65536] = 1
  130 + mask[jizhun != 65536] = 0
  131 + mask2[jizhun == 65536] = 0
  132 + mask2[jizhun != 65536] = 1
  133 + # 掩膜计算
  134 + for i, d in enumerate(empty_list):
  135 + empty_list[i] = empty_list[i] * mask + data[:, :, i] * mask2
  136 +
  137 + for ii in [0, 1, 2]:
  138 + # opencv 颜色排序为GBR
  139 + pixel_array[:, :, 2 - ii] = empty_list[ii]
  140 +
  141 +
  142 + elif len(intersect_image) == 1:
  143 + # 该影像的服务器,随机选取一个
  144 + image = intersect_image[0]
  145 + image_servers = image.server.split(",")
  146 + indx = int(random.random() * len(image_servers))
  147 + image_server = image_servers[indx]
  148 + pixel_array_t = self.get_data(zoo, image_server, image, extent, bands, height, width)
  149 + pixel_array = numpy.zeros((height, width, 3), dtype=int)
  150 + for ii in [0, 1, 2]:
  151 + # opencv 颜色排序为GBR
  152 + pixel_array[:, :, 2 - ii] = pixel_array_t[:, :, ii]
99 153
100   - intersect_image = [im for im in images if self.determin_intersect(json.loads(im.extent),extent)]
101 154
102   - pixel_array = numpy.zeros((256, 256,3), dtype=int)
  155 + else:
  156 + # 结果矩阵
  157 + pixel_array = numpy.zeros((height, width, 3), dtype=int) + 65536
103 158
104   - for image in intersect_image:
105   - if image.host.__eq__("本地服务器"):
106   - data = self.get_local_data(image,extent,bands)
107   - else:
108   - ser = "{}:{}".format(image.host,image.port)
109   - if zoo.exists("/rpc/{}".format(ser)):
110   - data= self.get_remote_data(image,extent,bands)
111   - else:
112   - data = numpy.zeros((256, 256, 3), dtype=int) + 65536
113   -
114   - # 掩膜在中央接口生成
115   - mask = numpy.zeros((256, 256), dtype=int)
116   - mask2 = numpy.zeros((256, 256), dtype=int)
117   - jizhun = data[:, :, 0]
118   - mask[jizhun == 65536] = 1
119   - mask[jizhun != 65536] = 0
120   - mask2[jizhun == 65536] = 0
121   - mask2[jizhun != 65536] = 1
122   - # 掩膜计算
123   - for i, d in enumerate(empty_list):
124   - empty_list[i] = empty_list[i] * mask + data[:, :, i] * mask2
125   -
126   -
127   - for ii in [0, 1, 2]:
128   - # opencv 颜色排序为GBR
129   - pixel_array[:, :, 2 - ii] = empty_list[ii]
130   -
131   - #将图片生成在内存中,然后直接返回response
  159 + # 将图片生成在内存中,然后直接返回response
132 160 im_data = self.create_by_opencv(image_type, pixel_array, quality)
133   -
134 161 return Response(im_data, mimetype=image_type.lower())
135 162
136 163 except Exception as e:
... ... @@ -139,8 +166,7 @@ class Api(ApiTemplate):
139 166 result["message"] = e.__str__()
140 167 return result
141 168
142   -
143   - def determine_level(self,xysize,origin_extent,extent,max_level):
  169 + def determine_level(self, xysize, origin_extent, extent, max_level):
144 170 '''
145 171 根据范围判断调用金字塔的哪一层
146 172 :param xysize:
... ... @@ -152,28 +178,43 @@ class Api(ApiTemplate):
152 178 x = xysize[0]
153 179 y = xysize[1]
154 180 level = -1
155   - pixel = x*y * (((extent[2]-extent[0])*(extent[3]-extent[1]))/((origin_extent[2]-origin_extent[0])*(origin_extent[3]-origin_extent[1])))
156   - while pixel>100000 and level<max_level-1:
157   - level+=1
158   - x=x/2
159   - y=y/2
  181 + pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / (
  182 + (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1])))
  183 + while pixel > 100000 and level < max_level - 1:
  184 + level += 1
  185 + x = x / 2
  186 + y = y / 2
160 187 pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / (
161 188 (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1])))
162 189 return level
163 190
164   - def create_by_opencv(self,image_type, pixel_array, quality):
  191 + def create_by_opencv(self, image_type, pixel_array, quality):
165 192
166 193 if image_type.__eq__("image/jpeg") or image_type.__eq__("image/jpg"):
167 194 r, buf = cv2.imencode(".jpg", pixel_array, [cv2.IMWRITE_JPEG_QUALITY, quality])
168 195 image_out = buf.tobytes()
169 196 else:
170   - four = numpy.zeros((256, 256), dtype=int) + 255
  197 + height, width = pixel_array[:, :, 0].shape
  198 + four = numpy.zeros((height, width), dtype=int) + 255
171 199 four[pixel_array[:, :, 0] == 65536] = 0
172 200 r, buf = cv2.imencode(".png", numpy.dstack((pixel_array, four)))
173 201 image_out = buf.tobytes()
174 202 return image_out
175 203
176   - def get_remote_data(self,image,extent,bands):
  204 + def get_data(self, zoo, image_server, image, extent, bands, height, width):
  205 +
  206 + if image_server.__eq__("本地服务器"):
  207 + data = self.get_local_wms_data(image, extent, bands, height, width)
  208 + else:
  209 + ser = image_server
  210 + if zoo.exists("/rpc/{}".format(ser)):
  211 + data = self.get_remote_wms_data(image, extent, bands, height, width)
  212 + else:
  213 + data = numpy.zeros((height, width, 3), dtype=int) + 65536
  214 +
  215 + return data
  216 +
  217 + def get_remote_wms_data(self, image, extent, bands, height, width):
177 218 '''
178 219 通过RPC获取远程数据
179 220 :param image:
... ... @@ -181,24 +222,21 @@ class Api(ApiTemplate):
181 222 :param bands:
182 223 :return:
183 224 '''
184   -
185   - transport = TSocket.TSocket(image.host, image.port)
186   - transport = TTransport.TBufferedTransport(transport)
187   - protocol = TBinaryProtocol.TBinaryProtocol(transport)
188   - client = ImageDataService.Client(protocol)
189   - transport.open()
  225 + thrift_connect = ThriftConnect(image.server)
190 226 t1 = time.time()
191   - data = client.getData(image.path, extent, json.loads(image.extent), bands)
192   - transport.close()
193   - current_app.logger.info("time {}".format(time.time() - t1))
  227 + image_extent = image.origin_extent if abs(extent[0]) > 180 else image.geo_origin_extent
194 228
  229 + data = thrift_connect.client.getData(image.path, extent, json.loads(image_extent), bands, width, height)
  230 +
  231 + thrift_connect.close()
  232 + current_app.logger.info("time {}".format(time.time() - t1))
195 233 data = gzip.decompress(data)
196   - data = numpy.frombuffer(data, dtype=int)
197   - data = data.reshape((256, 256, 3))
  234 + data = numpy.frombuffer(data, dtype='int64')
  235 + data = data.reshape((height, width, 3))
198 236
199 237 return data
200 238
201   - def get_local_data(self,image,extent,bands):
  239 + def get_local_wms_data(self, image, extent, bands, height, width):
202 240 '''
203 241 获取本地数据
204 242 :param image:
... ... @@ -206,7 +244,7 @@ class Api(ApiTemplate):
206 244 :param bands:
207 245 :return:
208 246 '''
209   - pixel_array = numpy.zeros((256, 256, 3), dtype=int)
  247 + pixel_array = numpy.zeros((height, width, 3), dtype=int)
210 248 ceng = 0
211 249 img: Dataset = gdal.Open(image.path, 0)
212 250 t1 = time.time()
... ... @@ -214,14 +252,16 @@ class Api(ApiTemplate):
214 252
215 253 # 自决定金字塔等级
216 254 xysize = [img.RasterXSize, img.RasterYSize]
217   - origin_extent = image.extent
  255 +
  256 + origin_extent = image.origin_extent if abs(extent[0]) > 180 else image.geo_origin_extent
218 257 band_data: Band = img.GetRasterBand(band)
  258 +
219 259 max_level = band_data.GetOverviewCount()
220 260
221 261 # 超出空间范围
222 262 if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[
223 263 3] or extent[3] < origin_extent[1]:
224   - empty = numpy.zeros((256, 256), dtype=int) + 65536
  264 + empty = numpy.zeros((height, width), dtype=int) + 65536
225 265 # 空间范围相交
226 266 else:
227 267 image_level = self.determine_level(xysize, origin_extent, extent, max_level)
... ... @@ -253,7 +293,7 @@ class Api(ApiTemplate):
253 293
254 294 y_g = math.ceil((extent[3] - extent[1]) / grid_y)
255 295
256   - empty = overview.ReadAsArray(off_x, off_y, x_g, y_g, 256, 256)
  296 + empty = overview.ReadAsArray(off_x, off_y, x_g, y_g, width, height)
257 297
258 298
259 299 # 部分相交
... ... @@ -276,8 +316,8 @@ class Api(ApiTemplate):
276 316 # 相对于出图的偏移量
277 317
278 318 # 出图的网格大小
279   - out_grid_x = (extent[2] - extent[0]) / (256 * 1.0)
280   - out_grid_y = (extent[3] - extent[1]) / (256 * 1.0)
  319 + out_grid_x = (extent[2] - extent[0]) / (width * 1.0)
  320 + out_grid_y = (extent[3] - extent[1]) / (height * 1.0)
281 321
282 322 out_off_x = int(math.ceil((inter_extent[0] - extent[0]) / out_grid_x))
283 323 out_off_y = int(math.ceil((extent[3] - inter_extent[3]) / out_grid_y))
... ... @@ -290,7 +330,7 @@ class Api(ApiTemplate):
290 330 overview_raster: ndarray = overview.ReadAsArray(off_x, off_y, x_g, y_g, out_x_g,
291 331 out_y_g)
292 332
293   - dat = numpy.zeros((256, 256), dtype=int) + 65536
  333 + dat = numpy.zeros((height, width), dtype=int) + 65536
294 334 dat[out_off_y:out_off_y + out_y_g, out_off_x:out_off_x + out_x_g] = overview_raster
295 335
296 336 empty = dat
... ... @@ -299,11 +339,43 @@ class Api(ApiTemplate):
299 339 ceng += 1
300 340 return pixel_array
301 341
302   - def determin_intersect(self,extent1,extent2):
  342 + def determin_intersect(self, extent1, extent2):
303 343 g1 = GeometryAdapter.envelop_2_polygon(extent1)
304 344 g2 = GeometryAdapter.envelop_2_polygon(extent2)
305 345 return g1.Intersect(g2)
306 346
  347 + api_doc = {
  348 + "tags": ["影像接口"],
  349 + "parameters": [
  350 + {"name": "guid",
  351 + "in": "formData",
  352 + "type": "string"},
  353 + {"name": "tilematrix",
  354 + "in": "formData",
  355 + "type": "string"},
  356 + {"name": "tilerow",
  357 + "in": "formData",
  358 + "type": "string"},
  359 + {"name": "tilecol",
  360 + "in": "formData",
  361 + "type": "string"},
  362 + {"name": "format",
  363 + "in": "formData",
  364 + "type": "string"},
  365 + {"name": "quality",
  366 + "in": "formData",
  367 + "type": "string"}
  368 +
  369 + ],
  370 + "responses": {
  371 + 200: {
  372 + "schema": {
  373 + "properties": {
  374 + }
  375 + }
  376 + }
  377 + }
  378 + }
307 379
308 380 class MyThread(Thread):
309 381 def __init__(self,func,args=()):
... ... @@ -318,18 +390,5 @@ class MyThread(Thread):
318 390 except Exception:
319 391 return None
320 392
321   -api_doc={
322   -"tags":["影像接口"],
323   -"parameters":[
324 393
325   -],
326   -"responses":{
327   - 200:{
328   - "schema":{
329   - "properties":{
330   - }
331   - }
332   - }
333   - }
334   -}
335 394
... ...
  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.image.models import ImageService,Image
  20 +from app.models import db
  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 +import os
  28 +import json
  29 +from kazoo.client import KazooClient
  30 +from app import GLOBAL_DIC
  31 +from threading import Thread
  32 +from thrift.transport import TSocket
  33 +from thrift.transport import TTransport
  34 +from thrift.protocol import TBinaryProtocol
  35 +from .ImageDataService import ImageDataService
  36 +from flask import current_app
  37 +import gzip
  38 +import random
  39 +class Api(ApiTemplate):
  40 +
  41 + api_name = "切片"
  42 +
  43 + def __init__(self,guid,level, row, col):
  44 + super().__init__()
  45 + self.guid = guid
  46 + self.level = level
  47 + self.row = row
  48 + self.col = col
  49 +
  50 + def process(self):
  51 +
  52 + result = {}
  53 + parameter: dict = self.para
  54 +
  55 + try:
  56 + if parameter.get("guid"):
  57 + self.guid = parameter.get("guid")
  58 +
  59 + image_service = ImageService.query.filter_by(guid = self.guid).one_or_none()
  60 + images = image_service.images.all()
  61 +
  62 + zoo = GLOBAL_DIC.get("zookeeper")
  63 + if zoo is None:
  64 + zoo :KazooClient = KazooClient(hosts=configure.zookeeper, timeout=100)
  65 + zoo.start()
  66 + GLOBAL_DIC["zookeeper"] = zoo
  67 + else :
  68 + if not zoo.connected:
  69 + zoo.start()
  70 +
  71 + bands = [1, 2, 3]
  72 +
  73 +
  74 + # 转换参数
  75 + parameter = ParameterUtil.to_lower(parameter)
  76 +
  77 +
  78 + if parameter.get("tilematrix"):
  79 + if parameter.get("tilematrix").__contains__(":"):
  80 + self.level = int(parameter.get("tilematrix").split(":")[-1])
  81 + else:
  82 + self.level = int(parameter.get("tilematrix"))
  83 + if parameter.get("tilerow"):
  84 + self.row = int(parameter.get("tilerow"))
  85 + if parameter.get("tilecol"):
  86 + self.col = int(parameter.get("tilecol"))
  87 +
  88 + image_type = parameter.get("format") if parameter.get("format") else "image/png"
  89 + quality = int(parameter.get("quality")) if parameter.get("quality") else 30
  90 + slice_para = json.loads(image_service.slice_scheme)
  91 + extent = SliceScheme.get_polygon(slice_para, self.level, self.row, self.col)
  92 +
  93 +
  94 +
  95 + # 多线程获取分布式数据
  96 +
  97 + intersect_image = [im for im in images if self.determin_intersect(json.loads(im.extent),extent)]
  98 +
  99 + pixel_array = numpy.zeros((256, 256,3), dtype=int)
  100 +
  101 + if len(intersect_image) > 1:
  102 +
  103 + # 结果矩阵
  104 + empty_list = [numpy.zeros((256,256), dtype=int) + 65536,
  105 + numpy.zeros((256,256), dtype=int) + 65536,
  106 + numpy.zeros((256,256), dtype=int) + 65536]
  107 +
  108 + pixel_array = numpy.zeros((256,256,3), dtype=int)
  109 + thread_list = []
  110 +
  111 + for image in intersect_image:
  112 + #该影像的服务器,随机选取一个
  113 + image_servers = image.server.split(",")
  114 + indx = int(random.random()*len(image_servers))
  115 + image_server = image_servers[indx]
  116 +
  117 + thread: MyThread = MyThread(self.get_data, args=(zoo,image_server,image,extent,bands))
  118 + thread.start()
  119 + thread_list.append(thread)
  120 +
  121 +
  122 + for thread in thread_list:
  123 + thread.join()
  124 + data = thread.get_result()
  125 +
  126 + # 掩膜在中央接口生成,合图
  127 + mask = numpy.zeros((256,256), dtype=int)
  128 + mask2 = numpy.zeros((256,256), dtype=int)
  129 + jizhun = data[:, :, 0]
  130 + mask[jizhun == 65536] = 1
  131 + mask[jizhun != 65536] = 0
  132 + mask2[jizhun == 65536] = 0
  133 + mask2[jizhun != 65536] = 1
  134 + # 掩膜计算
  135 + for i, d in enumerate(empty_list):
  136 + empty_list[i] = empty_list[i] * mask + data[:, :, i] * mask2
  137 + for ii in [0, 1, 2]:
  138 + # opencv 颜色排序为GBR
  139 + pixel_array[:, :, 2 - ii] = empty_list[ii]
  140 +
  141 + elif len(intersect_image) == 1:
  142 +
  143 + # 该影像的服务器,随机选取一个
  144 + image = intersect_image[0]
  145 + image_servers = image.server.split(",")
  146 + indx = int(random.random() * len(image_servers))
  147 + image_server = image_servers[indx]
  148 + pixel_array_t = self.get_data(zoo, image_server, image, extent, bands)
  149 + pixel_array = numpy.zeros((256,256, 3), dtype=int)
  150 + for ii in [0, 1, 2]:
  151 + # opencv 颜色排序为GBR
  152 + pixel_array[:, :, 2 - ii] = pixel_array_t[:, :, ii]
  153 +
  154 + else:
  155 + # 结果矩阵
  156 + pixel_array = numpy.zeros((256, 256, 3), dtype=int) + 65536
  157 +
  158 + #将图片生成在内存中,然后直接返回response
  159 + im_data = self.create_by_opencv(image_type, pixel_array, quality)
  160 +
  161 + return Response(im_data, mimetype=image_type.lower())
  162 +
  163 + except Exception as e:
  164 + print(traceback.format_exc())
  165 + result["state"] = -1
  166 + result["message"] = e.__str__()
  167 + return result
  168 +
  169 +
  170 + def determine_level(self,xysize,origin_extent,extent,max_level):
  171 + '''
  172 + 根据范围判断调用金字塔的哪一层
  173 + :param xysize:
  174 + :param origin_extent:
  175 + :param extent:
  176 + :param max_level:
  177 + :return:
  178 + '''
  179 + x = xysize[0]
  180 + y = xysize[1]
  181 + level = -1
  182 + pixel = x*y * (((extent[2]-extent[0])*(extent[3]-extent[1]))/((origin_extent[2]-origin_extent[0])*(origin_extent[3]-origin_extent[1])))
  183 + while pixel>100000 and level<max_level-1:
  184 + level+=1
  185 + x=x/2
  186 + y=y/2
  187 + pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / (
  188 + (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1])))
  189 + return level
  190 +
  191 + def create_by_opencv(self,image_type, pixel_array, quality):
  192 +
  193 + if image_type.__eq__("image/jpeg") or image_type.__eq__("image/jpg"):
  194 + r, buf = cv2.imencode(".jpg", pixel_array, [cv2.IMWRITE_JPEG_QUALITY, quality])
  195 + image_out = buf.tobytes()
  196 + else:
  197 + four = numpy.zeros((256, 256), dtype=int) + 255
  198 + four[pixel_array[:, :, 0] == 65536] = 0
  199 + r, buf = cv2.imencode(".png", numpy.dstack((pixel_array, four)))
  200 + image_out = buf.tobytes()
  201 + return image_out
  202 +
  203 + def get_data(self,zoo,image_server,image,extent,bands):
  204 +
  205 + if image_server.__eq__("本地服务器"):
  206 + data = self.get_local_data(image, extent, bands)
  207 + else:
  208 + ser = image_server
  209 + if zoo.exists("/rpc/{}".format(ser)):
  210 + data = self.get_remote_data(image, extent)
  211 + else:
  212 + data = numpy.zeros((256, 256, 3), dtype=int) + 65536
  213 + return data
  214 +
  215 +
  216 + def get_remote_data(self,image,extent,bands):
  217 + '''
  218 + 通过RPC获取远程数据
  219 + :param image:
  220 + :param extent:
  221 + :param bands:
  222 + :return:
  223 + '''
  224 +
  225 + transport = TSocket.TSocket(image.host, image.port)
  226 + transport = TTransport.TBufferedTransport(transport)
  227 + protocol = TBinaryProtocol.TBinaryProtocol(transport)
  228 + client = ImageDataService.Client(protocol)
  229 + transport.open()
  230 + t1 = time.time()
  231 + data = client.getData(image.path, extent, json.loads(image.extent), bands,256,256)
  232 + transport.close()
  233 + current_app.logger.info("time {}".format(time.time() - t1))
  234 +
  235 + data = gzip.decompress(data)
  236 + data = numpy.frombuffer(data, dtype=int)
  237 + data = data.reshape((256, 256, 3))
  238 +
  239 + return data
  240 +
  241 + def get_local_data(self,image,extent,bands):
  242 + '''
  243 + 获取本地数据
  244 + :param image:
  245 + :param extent:
  246 + :param bands:
  247 + :return:
  248 + '''
  249 + pixel_array = numpy.zeros((256, 256, 3), dtype=int)
  250 + ceng = 0
  251 + img: Dataset = gdal.Open(image.path, 0)
  252 + t1 = time.time()
  253 + for band in bands:
  254 +
  255 + # 自决定金字塔等级
  256 + xysize = [img.RasterXSize, img.RasterYSize]
  257 + origin_extent = image.extent
  258 + band_data: Band = img.GetRasterBand(band)
  259 + max_level = band_data.GetOverviewCount()
  260 +
  261 + # 超出空间范围
  262 + if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[
  263 + 3] or extent[3] < origin_extent[1]:
  264 + empty = numpy.zeros((256, 256), dtype=int) + 65536
  265 + # 空间范围相交
  266 + else:
  267 + image_level = self.determine_level(xysize, origin_extent, extent, max_level)
  268 +
  269 + if image_level == -1:
  270 + overview = band_data
  271 + else:
  272 + try:
  273 + overview: Band = band_data.GetOverview(image_level)
  274 + except:
  275 + raise Exception("该影像不存在该级别的金字塔数据!")
  276 + ox = overview.XSize
  277 + oy = overview.YSize
  278 +
  279 + # 网格大小
  280 + grid_x = (origin_extent[2] - origin_extent[0]) / (ox * 1.0)
  281 + grid_y = (origin_extent[3] - origin_extent[1]) / (oy * 1.0)
  282 +
  283 + # 完全在影像范围内
  284 + if extent[0] > origin_extent[0] and extent[1] > origin_extent[1] and extent[2] < \
  285 + origin_extent[2] and extent[3] < origin_extent[3]:
  286 +
  287 + # 网格偏移量
  288 + off_x = math.floor((extent[0] - origin_extent[0]) / grid_x)
  289 + off_y = math.floor((origin_extent[3] - extent[3]) / grid_y)
  290 +
  291 + # 截取后网格个数
  292 + x_g = math.ceil((extent[2] - extent[0]) / grid_x)
  293 +
  294 + y_g = math.ceil((extent[3] - extent[1]) / grid_y)
  295 +
  296 + empty = overview.ReadAsArray(off_x, off_y, x_g, y_g, 256, 256)
  297 +
  298 +
  299 + # 部分相交
  300 + else:
  301 +
  302 + inter_extent = [0, 0, 0, 0]
  303 + inter_extent[0] = origin_extent[0] if origin_extent[0] > extent[0] else extent[0]
  304 + inter_extent[1] = origin_extent[1] if origin_extent[1] > extent[1] else extent[1]
  305 + inter_extent[2] = origin_extent[2] if origin_extent[2] < extent[2] else extent[2]
  306 + inter_extent[3] = origin_extent[3] if origin_extent[3] < extent[3] else extent[3]
  307 +
  308 + # 网格偏移量
  309 + off_x = math.floor((inter_extent[0] - origin_extent[0]) / grid_x)
  310 + off_y = math.floor((origin_extent[3] - inter_extent[3]) / grid_y)
  311 +
  312 + # 截取后网格个数
  313 + x_g = math.floor((inter_extent[2] - inter_extent[0]) / grid_x)
  314 + y_g = math.floor((inter_extent[3] - inter_extent[1]) / grid_y)
  315 +
  316 + # 相对于出图的偏移量
  317 +
  318 + # 出图的网格大小
  319 + out_grid_x = (extent[2] - extent[0]) / (256 * 1.0)
  320 + out_grid_y = (extent[3] - extent[1]) / (256 * 1.0)
  321 +
  322 + out_off_x = int(math.ceil((inter_extent[0] - extent[0]) / out_grid_x))
  323 + out_off_y = int(math.ceil((extent[3] - inter_extent[3]) / out_grid_y))
  324 +
  325 + out_x_g = int(math.floor((inter_extent[2] - inter_extent[0]) / out_grid_x))
  326 + out_y_g = int(math.floor((inter_extent[3] - inter_extent[1]) / out_grid_y))
  327 +
  328 + # 相交部分在出图的哪个位置
  329 +
  330 + overview_raster: ndarray = overview.ReadAsArray(off_x, off_y, x_g, y_g, out_x_g,
  331 + out_y_g)
  332 +
  333 + dat = numpy.zeros((256, 256), dtype=int) + 65536
  334 + dat[out_off_y:out_off_y + out_y_g, out_off_x:out_off_x + out_x_g] = overview_raster
  335 +
  336 + empty = dat
  337 +
  338 + pixel_array[:, :, ceng] = empty
  339 + ceng += 1
  340 + return pixel_array
  341 +
  342 + def determin_intersect(self,extent1,extent2):
  343 + g1 = GeometryAdapter.envelop_2_polygon(extent1)
  344 + g2 = GeometryAdapter.envelop_2_polygon(extent2)
  345 + return g1.Intersect(g2)
  346 +
  347 + api_doc = {
  348 + "tags": ["影像接口"],
  349 + "parameters": [
  350 + {"name": "guid",
  351 + "in": "formData",
  352 + "type": "string"},
  353 + {"name": "tilematrix",
  354 + "in": "formData",
  355 + "type": "string"},
  356 + {"name": "tilerow",
  357 + "in": "formData",
  358 + "type": "string"},
  359 + {"name": "tilecol",
  360 + "in": "formData",
  361 + "type": "string"},
  362 + {"name": "format",
  363 + "in": "formData",
  364 + "type": "string"},
  365 + {"name": "quality",
  366 + "in": "formData",
  367 + "type": "string"}
  368 +
  369 + ],
  370 + "responses": {
  371 + 200: {
  372 + "schema": {
  373 + "properties": {
  374 + }
  375 + }
  376 + }
  377 + }
  378 + }
  379 +
  380 +class MyThread(Thread):
  381 + def __init__(self,func,args=()):
  382 + super(MyThread,self).__init__()
  383 + self.func = func
  384 + self.args = args
  385 + def run(self):
  386 + self.result = self.func(*self.args)
  387 + def get_result(self):
  388 + try:
  389 + return self.result
  390 + except Exception:
  391 + return None
  392 +
  393 +
  394 +
... ...
  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 random
  14 +import time
  15 +import cv2
  16 +from app.modules.image.models import ImageService
  17 +from app.util.component.ApiTemplate import ApiTemplate
  18 +from app.util.component.GeometryAdapter import GeometryAdapter
  19 +from app.util.component.ThriftConnect import ThriftConnect
  20 +from app.util.component.ParameterUtil import ParameterUtil
  21 +import json
  22 +from kazoo.client import KazooClient
  23 +from app import GLOBAL_DIC
  24 +from threading import Thread
  25 +from flask import current_app
  26 +import gzip
  27 +
  28 +class Api(ApiTemplate):
  29 +
  30 + api_name = "WMS"
  31 +
  32 + def process(self):
  33 +
  34 + result = {}
  35 + parameter: dict = self.para
  36 +
  37 + try:
  38 +
  39 + parameter = ParameterUtil.to_lower(parameter)
  40 + guid = parameter.get("guid")
  41 + bbox = parameter.get("bbox")
  42 + width = int(parameter.get("width")) if parameter.get("width") else 256
  43 + height = int(parameter.get("height")) if parameter.get("height") else 256
  44 + image_type = parameter.get("format") if parameter.get("format") else "image/png"
  45 + quality = int(parameter.get("quality")) if parameter.get("quality") else 30
  46 +
  47 +
  48 +
  49 +
  50 + #缓存起来
  51 + image_service = ImageService.query.filter_by(guid = guid).one_or_none()
  52 + images = image_service.images.all()
  53 +
  54 + re = parameter.get("request")
  55 +
  56 + if re and re.__eq__("GetCapabilities"):
  57 + return self.get_capabilities(image_service)
  58 +
  59 + zoo = GLOBAL_DIC.get("zookeeper")
  60 + if zoo is None:
  61 + zoo :KazooClient = KazooClient(hosts=configure.zookeeper, timeout=100)
  62 + zoo.start()
  63 + GLOBAL_DIC["zookeeper"] = zoo
  64 + else :
  65 + if not zoo.connected:
  66 + zoo.start()
  67 +
  68 + bands = [1, 2, 3]
  69 + extent = [float(x) for x in bbox.split(",")]
  70 + extent = [extent[1],extent[0],extent[3],extent[2]]
  71 +
  72 + if abs(extent[0])>180:
  73 + intersect_image = [im for im in images if self.determin_intersect(json.loads(im.origin_extent),extent)]
  74 + else:
  75 + intersect_image = [im for im in images if self.determin_intersect(json.loads(im.geo_origin_extent), extent)]
  76 +
  77 + if len(intersect_image)>1:
  78 +
  79 + # 结果矩阵
  80 + empty_list = [numpy.zeros((height,width), dtype=int) + 65536,
  81 + numpy.zeros((height,width), dtype=int) + 65536,
  82 + numpy.zeros((height,width), dtype=int) + 65536]
  83 +
  84 + pixel_array = numpy.zeros((height,width,3), dtype=int)
  85 + thread_list = []
  86 +
  87 + for image in intersect_image:
  88 + #该影像的服务器,随机选取一个
  89 + image_servers = image.server.split(",")
  90 + indx = int(random.random()*len(image_servers))
  91 + image_server = image_servers[indx]
  92 +
  93 + thread: MyThread = MyThread(self.get_data, args=(zoo,image_server,image,extent,bands,height,width))
  94 + thread.start()
  95 + thread_list.append(thread)
  96 +
  97 +
  98 + for thread in thread_list:
  99 + thread.join()
  100 + data = thread.get_result()
  101 +
  102 + # 掩膜在中央接口生成,合图
  103 + mask = numpy.zeros((height,width), dtype=int)
  104 + mask2 = numpy.zeros((height,width), dtype=int)
  105 + jizhun = data[:, :, 0]
  106 + mask[jizhun == 65536] = 1
  107 + mask[jizhun != 65536] = 0
  108 + mask2[jizhun == 65536] = 0
  109 + mask2[jizhun != 65536] = 1
  110 + # 掩膜计算
  111 + for i, d in enumerate(empty_list):
  112 + empty_list[i] = empty_list[i] * mask + data[:, :, i] * mask2
  113 +
  114 + for ii in [0, 1, 2]:
  115 + # opencv 颜色排序为GBR
  116 + pixel_array[:, :, 2 - ii] = empty_list[ii]
  117 +
  118 +
  119 + elif len(intersect_image)==1:
  120 + # 该影像的服务器,随机选取一个
  121 + image = intersect_image[0]
  122 + image_servers = image.server.split(",")
  123 + indx = int(random.random() * len(image_servers))
  124 + image_server = image_servers[indx]
  125 + pixel_array_t = self.get_data(zoo,image_server,image,extent,bands,height,width)
  126 + pixel_array = numpy.zeros((height, width, 3), dtype=int)
  127 + for ii in [0, 1, 2]:
  128 + # opencv 颜色排序为GBR
  129 + pixel_array[:, :, 2 - ii] = pixel_array_t[:, :, ii]
  130 + else:
  131 + # 结果矩阵
  132 + pixel_array = numpy.zeros((height, width, 3), dtype=int)+65536
  133 +
  134 + # 将图片生成在内存中,然后直接返回response
  135 + im_data = self.create_by_opencv(image_type, pixel_array, quality)
  136 + return Response(im_data, mimetype=image_type.lower())
  137 +
  138 + except Exception as e:
  139 + print(traceback.format_exc())
  140 + result["state"] = -1
  141 + result["message"] = e.__str__()
  142 + return result
  143 +
  144 +
  145 + def determine_level(self,xysize,origin_extent,extent,max_level):
  146 + '''
  147 + 根据范围判断调用金字塔的哪一层
  148 + :param xysize:
  149 + :param origin_extent:
  150 + :param extent:
  151 + :param max_level:
  152 + :return:
  153 + '''
  154 + x = xysize[0]
  155 + y = xysize[1]
  156 + level = -1
  157 + pixel = x*y * (((extent[2]-extent[0])*(extent[3]-extent[1]))/((origin_extent[2]-origin_extent[0])*(origin_extent[3]-origin_extent[1])))
  158 + while pixel>100000 and level<max_level-1:
  159 + level+=1
  160 + x=x/2
  161 + y=y/2
  162 + pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / (
  163 + (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1])))
  164 + return level
  165 +
  166 + def create_by_opencv(self,image_type, pixel_array, quality):
  167 +
  168 + if image_type.__eq__("image/jpeg") or image_type.__eq__("image/jpg"):
  169 + r, buf = cv2.imencode(".jpg", pixel_array, [cv2.IMWRITE_JPEG_QUALITY, quality])
  170 + image_out = buf.tobytes()
  171 + else:
  172 + height, width = pixel_array[:, :, 0].shape
  173 + four = numpy.zeros((height,width), dtype=int) + 255
  174 + four[pixel_array[:, :, 0] == 65536] = 0
  175 + r, buf = cv2.imencode(".png", numpy.dstack((pixel_array, four)))
  176 + image_out = buf.tobytes()
  177 + return image_out
  178 +
  179 + def get_data(self,zoo,image_server,image,extent,bands,height,width):
  180 +
  181 + if image_server.__eq__("本地服务器"):
  182 + data = self.get_local_wms_data(image, extent, bands, height, width)
  183 + else:
  184 + ser = image_server
  185 + if zoo.exists("/rpc/{}".format(ser)):
  186 + data = self.get_remote_wms_data(image, extent, bands, height, width)
  187 + else:
  188 + data = numpy.zeros((height, width, 3), dtype=int) + 65536
  189 +
  190 + return data
  191 +
  192 +
  193 +
  194 + def get_remote_wms_data(self,image,extent,bands,height,width):
  195 + '''
  196 + 通过RPC获取远程数据
  197 + :param image:
  198 + :param extent:
  199 + :param bands:
  200 + :return:
  201 + '''
  202 + thrift_connect = ThriftConnect(image.server)
  203 + t1 = time.time()
  204 + image_extent = image.origin_extent if abs(extent[0])>180 else image.geo_origin_extent
  205 +
  206 + data = thrift_connect.client.getData(image.path, extent, json.loads(image_extent), bands,width,height)
  207 +
  208 + thrift_connect.close()
  209 + current_app.logger.info("time {}".format(time.time() - t1))
  210 + data = gzip.decompress(data)
  211 + data = numpy.frombuffer(data, dtype='int64')
  212 + data = data.reshape((height,width, 3))
  213 +
  214 + return data
  215 +
  216 + def get_local_wms_data(self,image,extent,bands,height,width):
  217 + '''
  218 + 获取本地数据
  219 + :param image:
  220 + :param extent:
  221 + :param bands:
  222 + :return:
  223 + '''
  224 + pixel_array = numpy.zeros((height,width, 3), dtype=int)
  225 + ceng = 0
  226 + img: Dataset = gdal.Open(image.path, 0)
  227 + t1 = time.time()
  228 + for band in bands:
  229 +
  230 + # 自决定金字塔等级
  231 + xysize = [img.RasterXSize, img.RasterYSize]
  232 +
  233 + origin_extent = image.origin_extent if abs(extent[0]) > 180 else image.geo_origin_extent
  234 + band_data: Band = img.GetRasterBand(band)
  235 +
  236 + max_level = band_data.GetOverviewCount()
  237 +
  238 + # 超出空间范围
  239 + if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[
  240 + 3] or extent[3] < origin_extent[1]:
  241 + empty = numpy.zeros((height,width), dtype=int) + 65536
  242 + # 空间范围相交
  243 + else:
  244 + image_level = self.determine_level(xysize, origin_extent, extent, max_level)
  245 +
  246 + if image_level == -1:
  247 + overview = band_data
  248 + else:
  249 + try:
  250 + overview: Band = band_data.GetOverview(image_level)
  251 + except:
  252 + raise Exception("该影像不存在该级别的金字塔数据!")
  253 + ox = overview.XSize
  254 + oy = overview.YSize
  255 +
  256 + # 网格大小
  257 + grid_x = (origin_extent[2] - origin_extent[0]) / (ox * 1.0)
  258 + grid_y = (origin_extent[3] - origin_extent[1]) / (oy * 1.0)
  259 +
  260 + # 完全在影像范围内
  261 + if extent[0] > origin_extent[0] and extent[1] > origin_extent[1] and extent[2] < \
  262 + origin_extent[2] and extent[3] < origin_extent[3]:
  263 +
  264 + # 网格偏移量
  265 + off_x = math.floor((extent[0] - origin_extent[0]) / grid_x)
  266 + off_y = math.floor((origin_extent[3] - extent[3]) / grid_y)
  267 +
  268 + # 截取后网格个数
  269 + x_g = math.ceil((extent[2] - extent[0]) / grid_x)
  270 +
  271 + y_g = math.ceil((extent[3] - extent[1]) / grid_y)
  272 +
  273 + empty = overview.ReadAsArray(off_x, off_y, x_g, y_g, width,height)
  274 +
  275 +
  276 + # 部分相交
  277 + else:
  278 +
  279 + inter_extent = [0, 0, 0, 0]
  280 + inter_extent[0] = origin_extent[0] if origin_extent[0] > extent[0] else extent[0]
  281 + inter_extent[1] = origin_extent[1] if origin_extent[1] > extent[1] else extent[1]
  282 + inter_extent[2] = origin_extent[2] if origin_extent[2] < extent[2] else extent[2]
  283 + inter_extent[3] = origin_extent[3] if origin_extent[3] < extent[3] else extent[3]
  284 +
  285 + # 网格偏移量
  286 + off_x = math.floor((inter_extent[0] - origin_extent[0]) / grid_x)
  287 + off_y = math.floor((origin_extent[3] - inter_extent[3]) / grid_y)
  288 +
  289 + # 截取后网格个数
  290 + x_g = math.floor((inter_extent[2] - inter_extent[0]) / grid_x)
  291 + y_g = math.floor((inter_extent[3] - inter_extent[1]) / grid_y)
  292 +
  293 + # 相对于出图的偏移量
  294 +
  295 + # 出图的网格大小
  296 + out_grid_x = (extent[2] - extent[0]) / (width * 1.0)
  297 + out_grid_y = (extent[3] - extent[1]) / (height * 1.0)
  298 +
  299 + out_off_x = int(math.ceil((inter_extent[0] - extent[0]) / out_grid_x))
  300 + out_off_y = int(math.ceil((extent[3] - inter_extent[3]) / out_grid_y))
  301 +
  302 + out_x_g = int(math.floor((inter_extent[2] - inter_extent[0]) / out_grid_x))
  303 + out_y_g = int(math.floor((inter_extent[3] - inter_extent[1]) / out_grid_y))
  304 +
  305 + # 相交部分在出图的哪个位置
  306 +
  307 + overview_raster: ndarray = overview.ReadAsArray(off_x, off_y, x_g, y_g, out_x_g,
  308 + out_y_g)
  309 +
  310 + dat = numpy.zeros((height,width), dtype=int) + 65536
  311 + dat[out_off_y:out_off_y + out_y_g, out_off_x:out_off_x + out_x_g] = overview_raster
  312 +
  313 + empty = dat
  314 +
  315 + pixel_array[:, :, ceng] = empty
  316 + ceng += 1
  317 + return pixel_array
  318 +
  319 + def determin_intersect(self,extent1,extent2):
  320 + g1 = GeometryAdapter.envelop_2_polygon(extent1)
  321 + g2 = GeometryAdapter.envelop_2_polygon(extent2)
  322 + return g1.Intersect(g2)
  323 +
  324 + def get_capabilities(self,image_service:ImageService):
  325 +
  326 + xml = '''<?xml version="1.0" encoding="utf-8" ?>
  327 + <WMS_Capabilities version="1.3.0">
  328 + <Service>
  329 + <Name>WMS</Name>
  330 + <Title>{service_title}</Title>
  331 + <Abstract>{abstract}</Abstract>
  332 + <Keywords>GIMS</Keywords>
  333 + <OnlineResource/>
  334 + <Fees>none</Fees>
  335 + <AccessConstraints>none</AccessConstraints>
  336 + </Service>
  337 + <Capability>
  338 + <Request>
  339 + <GetCapabilities>
  340 + <Format>text/xml</Format>
  341 + <DCPType>
  342 + <HTTP>
  343 + <Get>
  344 + <OnlineResource xlink:href="{url}" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink"/>
  345 + </Get>
  346 + </HTTP>
  347 + </DCPType>
  348 + </GetCapabilities>
  349 + <GetMap>
  350 + <Format>png</Format>
  351 + <Format>jpeg</Format>
  352 + <Format>gif</Format>
  353 + <Format>image/png</Format>
  354 + <Format>image/jpeg</Format>
  355 + <Format>image/gif</Format>
  356 + <DCPType>
  357 + <HTTP>
  358 + <Get>
  359 + <OnlineResource xlink:href="{url}" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink"/>
  360 + </Get>
  361 + </HTTP>
  362 + </DCPType>
  363 + </GetMap>
  364 + <Map>
  365 + <Format>
  366 + <PNG/>
  367 + <GIF/>
  368 + <JPG/>
  369 + </Format>
  370 + <DCPType>
  371 + <HTTP>
  372 + <Get onlineResource="{url}"/>
  373 + </HTTP>
  374 + </DCPType>
  375 + </Map>
  376 + <Capabilities>
  377 + <Format>
  378 + <WMS_XML/>
  379 + </Format>
  380 + <DCPType>
  381 + <HTTP>
  382 + <Get onlineResource="{url}"/>
  383 + </HTTP>
  384 + </DCPType>
  385 + </Capabilities>
  386 + <FeatureInfo>
  387 + <Format>
  388 + <XML/>
  389 + <MIME/>
  390 + </Format>
  391 + <DCPType>
  392 + <HTTP>
  393 + <Get onlineResource="{url}"/>
  394 + </HTTP>
  395 + </DCPType>
  396 + </FeatureInfo>
  397 + </Request>
  398 + <Exception>
  399 + <Format>
  400 + <WMS_XML/>
  401 + <INIMAGE/>
  402 + <BLANK/>
  403 + </Format>
  404 + </Exception>
  405 + <Layer>
  406 + <Name>{service_name}</Name>
  407 + <Title>{service_title}</Title>
  408 + <CRS>{crs}</CRS>
  409 + <BoundingBox CRS="{crs}" maxx="{maxx}" maxy="{maxy}" minx="{minx}" miny="{miny}"/>
  410 + <Layer queryable="1">
  411 + <CRS>{crs}</CRS>
  412 + <Name>{layer_name}</Name>
  413 + <Title>{layer_title}</Title>
  414 + <BoundingBox CRS="{crs}" maxx="{maxx}" maxy="{maxy}" minx="{minx}" miny="{miny}"/>
  415 + </Layer>
  416 + </Layer>
  417 + </Capability>
  418 + </WMS_Capabilities>'''
  419 +
  420 + extent = json.loads(image_service.extent)
  421 + xml = xml.format(service_title=image_service.name,
  422 + service_name=image_service.name,
  423 + abstract=image_service.description if image_service.description else "None" ,
  424 + crs="ESPG:4326",
  425 + layer_name=image_service.name,
  426 + layer_title=image_service.name,
  427 + maxx=extent[2],
  428 + maxy = extent[3],
  429 + minx = extent[0],
  430 + miny = extent[1],
  431 + url="http://{}/API/Image/WMS?guid={}".format(configure.deploy_ip_host,image_service.guid))
  432 +
  433 +
  434 + r = Response(response=xml, status=200, mimetype="application/xml")
  435 + r.headers["Content-Type"] = "text/xml; charset=utf-8"
  436 + return r
  437 +
  438 + api_doc = {
  439 + "tags": ["影像接口"],
  440 + "parameters": [
  441 + {"name": "guid",
  442 + "in": "query",
  443 + "type": "string"},
  444 + {"name": "bbox",
  445 + "in": "query",
  446 + "type": "string"},
  447 + {"name": "width",
  448 + "in": "query",
  449 + "type": "string"},
  450 + {"name": "height",
  451 + "in": "query",
  452 + "type": "string"},
  453 + {"name": "format",
  454 + "in": "query",
  455 + "type": "string"},
  456 + {"name": "quality",
  457 + "in": "query",
  458 + "type": "string"}
  459 + ],
  460 + "responses": {
  461 + 200: {
  462 + "schema": {
  463 + "properties": {
  464 + }
  465 + }
  466 + }
  467 + }
  468 + }
  469 +
  470 +class MyThread(Thread):
  471 + def __init__(self,func,args=()):
  472 + super(MyThread,self).__init__()
  473 + self.func = func
  474 + self.args = args
  475 + def run(self):
  476 + self.result = self.func(*self.args)
  477 + def get_result(self):
  478 + try:
  479 + return self.result
  480 + except Exception:
  481 + return None
  482 +
  483 +
  484 +
... ...
... ... @@ -4,7 +4,7 @@
4 4 #email: nheweijun@sina.com
5 5
6 6
7   -from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time,Binary
  7 +from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time,Binary,Float
8 8 from app.models import db
9 9
10 10
... ... @@ -16,21 +16,31 @@ class Image(db.Model):
16 16 __tablename__ = 'dmdms_image'
17 17 guid = Column(String(256), primary_key=True)
18 18 name = Column(String)
19   - alias=Column(String)
20   - raster_y_size=Column(Integer)
  19 + alias = Column(String)
  20 + raster_y_size = Column(Integer)
21 21 raster_x_size = Column(Integer)
22   - overview = Column(Integer)
23   - extent = Column(String)
  22 + overview_count = Column(Integer)
  23 + origin_extent = Column(String)
  24 + geo_origin_extent = Column(String)
24 25 null_value = Column(Integer)
25 26 available = Column(Integer)#影像是否可用,不可用可能在创建金字塔中
26   - bands = Column(Integer)
27   - path=Column(String)
28   - host=Column(String)
29   - port=Column(Integer)
  27 + band_count = Column(Integer)
  28 + path = Column(String)
  29 + server = Column(String)
  30 + # host=Column(String)
  31 + # port=Column(Integer)
  32 + size = Column(Float)
30 33 #坐标wkt
31   - projection = Column(Text)
  34 + sr_wkt = Column(Text)
  35 + sr_proj4 = Column(Text)
  36 + epsg = Column(Integer)
  37 + create_time = Column(DateTime)
  38 + update_time = Column(DateTime)
  39 + cell_x_size = Column(Float)
  40 + cell_y_size = Column(Float)
  41 + region = Column(Text)
32 42 #年份
33   - ym= Column(String(256))
  43 + ym = Column(String(256))
34 44
35 45 dmdms_image_rel = db.Table('dmdms_image_rel',
36 46 Column('image_guid',String, ForeignKey('dmdms_image.guid')),
... ... @@ -53,12 +63,34 @@ class ImageService(db.Model):
53 63 description = Column(Text)
54 64 slice_scheme = Column(Text)
55 65 extent = Column(String(256))
  66 + node = Column(Integer)
56 67 #可视范围geojson
57 68 visual_range = Column(Text)
58 69 #影像服务缩略图
59 70 overview = Column(Binary)
  71 +
60 72 images = db.relationship('Image',
61 73 secondary=dmdms_image_rel,
62 74 backref='image_services',
63 75 lazy='dynamic'
64 76 )
  77 +
  78 +
  79 +dmdms_image_tag_rel = db.Table('dmdms_image_tag_rel',
  80 + Column('image_guid',String, ForeignKey('dmdms_image.guid')),
  81 + Column('tag_guid', String, ForeignKey('dmdms_image_tag.guid'))
  82 + )
  83 +
  84 +class ImageTag(db.Model):
  85 + '''
  86 + 影像标签
  87 + '''
  88 + __tablename__ = 'dmdms_image_tag'
  89 + guid = Column(String(256), primary_key=True)
  90 + name=Column(String(256))
  91 + alias = Column(String(256))
  92 + images = db.relationship('Image',
  93 + secondary=dmdms_image_tag_rel,
  94 + backref='image_tags',
  95 + lazy='dynamic'
  96 + )
... ...
... ... @@ -51,11 +51,10 @@ class Api(ApiTemplate):
51 51 data = self.download_gdb(table_names, ds,database_guid)
52 52
53 53 result["data"] = data
54   - result["state"] = 1
  54 + result["result"] = True
55 55 except Exception as e:
56   - print(traceback.format_exc())
57   - result["message"]= e.__str__()
58   - result["state"]=-1
  56 + raise e
  57 +
59 58 finally:
60 59 if ds:
61 60 ds.Destroy()
... ...
... ... @@ -225,7 +225,8 @@ class EntryDataVacuate:
225 225 if geo is not None:
226 226 out_geom:Geometry = GeometryAdapter.change_geom(geo, geom_type)
227 227 out_feature.SetGeometry(out_geom)
228   -
  228 + # 出现fid为0经常有问题
  229 + out_feature.SetFID(out_feature.GetFID() + 1)
229 230 pg_layer.CreateFeature(out_feature)
230 231
231 232 #插入抽稀图层
... ...
  1 +# coding=utf-8
  2 +#author: 4N
  3 +#createtime: 2021/9/8
  4 +#email: nheweijun@sina.com
  5 +
  6 +from thrift.transport import TSocket
  7 +from thrift.transport import TTransport
  8 +from thrift.protocol import TBinaryProtocol
  9 +from app.modules.image.ImageDataService import ImageDataService
  10 +
  11 +class ThriftConnect:
  12 + '''
  13 + thrift连接类
  14 + '''
  15 +
  16 + client = None
  17 + transport = None
  18 +
  19 + def __init__(self,data_server):
  20 + host = data_server.split(":")[0]
  21 + port = int(data_server.split(":")[1])
  22 + self.transport: TSocket = TSocket.TSocket(host, port)
  23 + self.transport = TTransport.TBufferedTransport(self.transport)
  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()
\ No newline at end of file
... ...
1 1 # coding=utf-8
2 2
3 3 # 程序部署ip:host
4   -deploy_ip_host = "172.26.99.160:8840"
  4 +deploy_ip_host = "172.26.40.105:8840"
5 5 # 系统数据库
6 6
7   -SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.99.160:5432/dmap_dms_test"
  7 +SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.60.100:5432/dmap_manager"
8 8
9 9 # 指定精华表所在位置(必须为空间库),设置为None则存放在各自的实体库中
10 10 VACUATE_DB_URI = None
... ...
... ... @@ -359,6 +359,7 @@ WSGIDaemonProcess dmapmanager processes=4 threads=16 display-name=%{GROUP}
359 359 dmapmanager
360 360 #Authorization请求头顺利转发
361 361 On
  362 + %{GLOBAL}
362 363
363 364 / /usr/src/app/run.wsgi
364 365 <Directory /usr/>
... ...
... ... @@ -24,7 +24,7 @@ fi
24 24 #启动容器和apache
25 25 echo "正在启动容器..."
26 26 set="--privileged=true -e TZ="Asia/Shanghai" --restart=always -e ALLOW_IP_RANGE=0.0.0.0/0"
27   -docker run -d --name dmapmanager $set -p $port:80 -v $curPath:/usr/src/app -v $curPath/httpd.conf:/etc/httpd/conf/httpd.conf dci/dmapdms:4.0 /usr/sbin/init
  27 +docker run -d --name dmapmanager $set -p $port:80 -v $curPath:/usr/src/app -v $curPath/httpd.conf:/etc/httpd/conf/httpd.conf dci/dmapmanager:4.0 /usr/sbin/init
28 28 docker exec -d dmapmanager systemctl start httpd
29 29 sleep 5
30 30 curl localhost:$port/release
... ...
... ... @@ -18,6 +18,5 @@ import json
18 18 #
19 19 # print(sys.getsizeof(json.dumps(pixel_array.tolist())))
20 20 # print(sys.getsizeof((content)))
21   -
22   -for x in range(-3,3,1):
23   - print(x)
\ No newline at end of file
  21 +import random
  22 +print(int(random.random()*2))
\ No newline at end of file
... ...
  1 +#2021.09.10 Version:4.0.0
... ...
注册登录 后发表评论