提交 25ceb357b6f4dbec1ac5b23f7a2414f61be7093d

作者 nheweijun
1 个父辈 006d265f

架构重新设计之前

@@ -3,7 +3,7 @@ import base64 @@ -3,7 +3,7 @@ import base64
3 import os 3 import os
4 from flask_sqlalchemy import SQLAlchemy,Model 4 from flask_sqlalchemy import SQLAlchemy,Model
5 import importlib 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 from sqlalchemy.orm import relationship 7 from sqlalchemy.orm import relationship
8 import base64 8 import base64
9 from pyDes import * 9 from pyDes import *
@@ -198,3 +198,22 @@ class InsertingLayerName(db.Model): @@ -198,3 +198,22 @@ class InsertingLayerName(db.Model):
198 task_guid = Column(String(256)) 198 task_guid = Column(String(256))
199 name = Column(String(256)) 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,34 +146,35 @@ class Api(ApiTemplate):
146 table_guid = uuid.uuid1().__str__() 146 table_guid = uuid.uuid1().__str__()
147 147
148 geom_type = GeometryAdapter.get_geometry_type(layer) 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 except: 175 except:
150 StructurePrint.print("表{}注册失败!".format(l_name), "warn") 176 StructurePrint.print("表{}注册失败!".format(l_name), "warn")
151 continue 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 return spatial_table_name,tables 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,7 +24,7 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help':
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...]]') 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 print('') 25 print('')
26 print('Functions:') 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 print(' string getInfo(string path)') 28 print(' string getInfo(string path)')
29 print(' bool buildOverview(string path)') 29 print(' bool buildOverview(string path)')
30 print(' string getImageList(string path)') 30 print(' string getImageList(string path)')
@@ -108,10 +108,10 @@ client = ImageDataService.Client(protocol) @@ -108,10 +108,10 @@ client = ImageDataService.Client(protocol)
108 transport.open() 108 transport.open()
109 109
110 if cmd == 'getData': 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 sys.exit(1) 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 elif cmd == 'getInfo': 116 elif cmd == 'getInfo':
117 if len(args) != 1: 117 if len(args) != 1:
@@ -19,13 +19,15 @@ all_structs = [] @@ -19,13 +19,15 @@ all_structs = []
19 19
20 20
21 class Iface(object): 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 Parameters: 24 Parameters:
25 - path 25 - path
26 - queryRange 26 - queryRange
27 - originRange 27 - originRange
28 - bands 28 - bands
  29 + - width
  30 + - height
29 31
30 """ 32 """
31 pass 33 pass
@@ -62,25 +64,29 @@ class Client(Iface): @@ -62,25 +64,29 @@ class Client(Iface):
62 self._oprot = oprot 64 self._oprot = oprot
63 self._seqid = 0 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 Parameters: 69 Parameters:
68 - path 70 - path
69 - queryRange 71 - queryRange
70 - originRange 72 - originRange
71 - bands 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 return self.recv_getData() 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 self._oprot.writeMessageBegin('getData', TMessageType.CALL, self._seqid) 82 self._oprot.writeMessageBegin('getData', TMessageType.CALL, self._seqid)
79 args = getData_args() 83 args = getData_args()
80 args.path = path 84 args.path = path
81 args.queryRange = queryRange 85 args.queryRange = queryRange
82 args.originRange = originRange 86 args.originRange = originRange
83 args.bands = bands 87 args.bands = bands
  88 + args.width = width
  89 + args.height = height
84 args.write(self._oprot) 90 args.write(self._oprot)
85 self._oprot.writeMessageEnd() 91 self._oprot.writeMessageEnd()
86 self._oprot.trans.flush() 92 self._oprot.trans.flush()
@@ -233,7 +239,7 @@ class Processor(Iface, TProcessor): @@ -233,7 +239,7 @@ class Processor(Iface, TProcessor):
233 iprot.readMessageEnd() 239 iprot.readMessageEnd()
234 result = getData_result() 240 result = getData_result()
235 try: 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 msg_type = TMessageType.REPLY 243 msg_type = TMessageType.REPLY
238 except TTransport.TTransportException: 244 except TTransport.TTransportException:
239 raise 245 raise
@@ -329,15 +335,19 @@ class getData_args(object): @@ -329,15 +335,19 @@ class getData_args(object):
329 - queryRange 335 - queryRange
330 - originRange 336 - originRange
331 - bands 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 self.path = path 345 self.path = path
338 self.queryRange = queryRange 346 self.queryRange = queryRange
339 self.originRange = originRange 347 self.originRange = originRange
340 self.bands = bands 348 self.bands = bands
  349 + self.width = width
  350 + self.height = height
341 351
342 def read(self, iprot): 352 def read(self, iprot):
343 if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None: 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,6 +393,16 @@ class getData_args(object):
383 iprot.readListEnd() 393 iprot.readListEnd()
384 else: 394 else:
385 iprot.skip(ftype) 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 else: 406 else:
387 iprot.skip(ftype) 407 iprot.skip(ftype)
388 iprot.readFieldEnd() 408 iprot.readFieldEnd()
@@ -418,6 +438,14 @@ class getData_args(object): @@ -418,6 +438,14 @@ class getData_args(object):
418 oprot.writeI32(iter20) 438 oprot.writeI32(iter20)
419 oprot.writeListEnd() 439 oprot.writeListEnd()
420 oprot.writeFieldEnd() 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 oprot.writeFieldStop() 449 oprot.writeFieldStop()
422 oprot.writeStructEnd() 450 oprot.writeStructEnd()
423 451
@@ -441,6 +469,8 @@ getData_args.thrift_spec = ( @@ -441,6 +469,8 @@ getData_args.thrift_spec = (
441 (2, TType.LIST, 'queryRange', (TType.DOUBLE, None, False), None, ), # 2 469 (2, TType.LIST, 'queryRange', (TType.DOUBLE, None, False), None, ), # 2
442 (3, TType.LIST, 'originRange', (TType.DOUBLE, None, False), None, ), # 3 470 (3, TType.LIST, 'originRange', (TType.DOUBLE, None, False), None, ), # 3
443 (4, TType.LIST, 'bands', (TType.I32, None, False), None, ), # 4 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,7 +15,7 @@ from . import data_list
15 from . import capabilities 15 from . import capabilities
16 from . import image_list 16 from . import image_list
17 from . import image_tile 17 from . import image_tile
18 - 18 +from . import image_wms
19 19
20 class DataManager(BlueprintApi): 20 class DataManager(BlueprintApi):
21 21
@@ -101,4 +101,15 @@ class DataManager(BlueprintApi): @@ -101,4 +101,15 @@ class DataManager(BlueprintApi):
101 """ 101 """
102 切片服务 102 切片服务
103 """ 103 """
104 - return image_tile.Api("1",1,1,1).result  
  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
@@ -12,7 +12,7 @@ import json @@ -12,7 +12,7 @@ import json
12 from app.modules.image.ImageDataService import ImageDataService 12 from app.modules.image.ImageDataService import ImageDataService
13 from app.util.component.FileProcess import FileProcess 13 from app.util.component.FileProcess import FileProcess
14 import datetime 14 import datetime
15 - 15 +from app.util.component.ThriftConnect import ThriftConnect
16 import os 16 import os
17 class Api(ApiTemplate): 17 class Api(ApiTemplate):
18 18
@@ -56,20 +56,14 @@ class Api(ApiTemplate): @@ -56,20 +56,14 @@ class Api(ApiTemplate):
56 elif os.path.isdir(file_path): 56 elif os.path.isdir(file_path):
57 file_info["type"] = "dir" 57 file_info["type"] = "dir"
58 data_list.append(file_info) 58 data_list.append(file_info)
  59 +
59 data_list_sorted = sorted(data_list, key=lambda x: x["name"]) 60 data_list_sorted = sorted(data_list, key=lambda x: x["name"])
60 res["data"] = data_list_sorted 61 res["data"] = data_list_sorted
61 62
62 else: 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 res["data"] = info 67 res["data"] = info
74 68
75 res["result"] = True 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,7 +8,7 @@ from app.util.component.ApiTemplate import ApiTemplate
8 from app.util.component.ModelVisitor import ModelVisitor 8 from app.util.component.ModelVisitor import ModelVisitor
9 9
10 from app.modules.image.models import Image 10 from app.modules.image.models import Image
11 - 11 +from sqlalchemy import or_,and_
12 class Api(ApiTemplate): 12 class Api(ApiTemplate):
13 13
14 api_name = "影像数据List" 14 api_name = "影像数据List"
@@ -23,9 +23,19 @@ class Api(ApiTemplate): @@ -23,9 +23,19 @@ class Api(ApiTemplate):
23 23
24 alias = self.para.get("alias") 24 alias = self.para.get("alias")
25 name = self.para.get("name") 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 res["data"] = ModelVisitor.objects_to_jsonarray(images) 39 res["data"] = ModelVisitor.objects_to_jsonarray(images)
30 res["result"] = True 40 res["result"] = True
31 except Exception as e: 41 except Exception as e:
@@ -3,106 +3,138 @@ @@ -3,106 +3,138 @@
3 #createtime: 2021/7/19 3 #createtime: 2021/7/19
4 #email: nheweijun@sina.com 4 #email: nheweijun@sina.com
5 5
6 -from osgeo.ogr import * 6 +
7 from osgeo import gdal,ogr,osr 7 from osgeo import gdal,ogr,osr
8 from osgeo.gdal import Dataset,Band 8 from osgeo.gdal import Dataset,Band
9 from app.util.component.ApiTemplate import ApiTemplate 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 import json 12 import json
18 from .models import Image 13 from .models import Image
19 -from app.modules.image.ImageDataService import ImageDataService 14 +import datetime
20 from app.models import db 15 from app.models import db
21 import uuid 16 import uuid
22 import os 17 import os
  18 +import math
23 class Api(ApiTemplate): 19 class Api(ApiTemplate):
24 20
25 api_name = "注册影像数据" 21 api_name = "注册影像数据"
26 22
27 def process(self): 23 def process(self):
28 24
29 -  
30 - # 返回结果 25 + #可以注册一个目录
  26 + #返回结果
31 res = {} 27 res = {}
32 28
33 try: 29 try:
34 data_server = self.para.get("data_server") 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 else: 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 db.session.commit() 136 db.session.commit()
105 - res["data"] = guid 137 + # res["data"] = guid
106 res["result"] = True 138 res["result"] = True
107 139
108 except Exception as e: 140 except Exception as e:
@@ -110,7 +142,35 @@ class Api(ApiTemplate): @@ -110,7 +142,35 @@ class Api(ApiTemplate):
110 142
111 return res 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 api_doc = { 174 api_doc = {
115 "tags": ["影像接口"], 175 "tags": ["影像接口"],
116 "parameters": [ 176 "parameters": [
@@ -118,10 +178,10 @@ class Api(ApiTemplate): @@ -118,10 +178,10 @@ class Api(ApiTemplate):
118 "in": "formData", 178 "in": "formData",
119 "type": "string", 179 "type": "string",
120 "description": "data_server"}, 180 "description": "data_server"},
121 - {"name": "path", 181 + {"name": "paths",
122 "in": "formData", 182 "in": "formData",
123 "type": "string", 183 "type": "string",
124 - "description": "path"} 184 + "description": "paths"}
125 ], 185 ],
126 "responses": { 186 "responses": {
127 200: { 187 200: {
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 from app.util.component.ApiTemplate import ApiTemplate 7 from app.util.component.ApiTemplate import ApiTemplate
8 from app.util.component.ModelVisitor import ModelVisitor 8 from app.util.component.ModelVisitor import ModelVisitor
9 from app.modules.image.models import ImageService 9 from app.modules.image.models import ImageService
10 - 10 +from sqlalchemy import or_
11 11
12 class Api(ApiTemplate): 12 class Api(ApiTemplate):
13 13
@@ -32,8 +32,17 @@ class Api(ApiTemplate): @@ -32,8 +32,17 @@ class Api(ApiTemplate):
32 alias = self.para.get("alias") 32 alias = self.para.get("alias")
33 name = self.para.get("name") 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 res["data"] = ModelVisitor.objects_to_jsonarray(image_services) 47 res["data"] = ModelVisitor.objects_to_jsonarray(image_services)
39 res["result"] = True 48 res["result"] = True
@@ -11,6 +11,7 @@ from app.util.component.SliceScheme import SliceScheme @@ -11,6 +11,7 @@ from app.util.component.SliceScheme import SliceScheme
11 from app.util.component.FileProcess import FileProcess 11 from app.util.component.FileProcess import FileProcess
12 import os 12 import os
13 import json 13 import json
  14 +import datetime
14 class Api(ApiTemplate): 15 class Api(ApiTemplate):
15 16
16 api_name = "注册影像服务" 17 api_name = "注册影像服务"
@@ -32,13 +33,14 @@ class Api(ApiTemplate): @@ -32,13 +33,14 @@ class Api(ApiTemplate):
32 dir_path, store_file = FileProcess.save(parent) 33 dir_path, store_file = FileProcess.save(parent)
33 scheme = SliceScheme(store_file).parameter 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 service_exetent = [] 38 service_exetent = []
37 39
38 for g in guids: 40 for g in guids:
39 image = Image.query.filter_by(guid=g).one_or_none() 41 image = Image.query.filter_by(guid=g).one_or_none()
40 if image: 42 if image:
41 - image_extent = json.loads(image.extent) 43 + image_extent = json.loads(image.origin_extent)
42 if not service_exetent: 44 if not service_exetent:
43 service_exetent = image_extent 45 service_exetent = image_extent
44 else: 46 else:
@@ -50,6 +52,9 @@ class Api(ApiTemplate): @@ -50,6 +52,9 @@ class Api(ApiTemplate):
50 service.extent = json.dumps(service_exetent) 52 service.extent = json.dumps(service_exetent)
51 db.session.add(service) 53 db.session.add(service)
52 db.session.commit() 54 db.session.commit()
  55 +
  56 + #获得overview
  57 +
53 res["data"] = service_guid 58 res["data"] = service_guid
54 res["result"] = True 59 res["result"] = True
55 except Exception as e: 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,13 +29,11 @@ import json
29 from kazoo.client import KazooClient 29 from kazoo.client import KazooClient
30 from app import GLOBAL_DIC 30 from app import GLOBAL_DIC
31 from threading import Thread 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 from flask import current_app 34 from flask import current_app
37 import gzip 35 import gzip
38 - 36 +import random
39 class Api(ApiTemplate): 37 class Api(ApiTemplate):
40 38
41 api_name = "切片" 39 api_name = "切片"
@@ -90,47 +88,76 @@ class Api(ApiTemplate): @@ -90,47 +88,76 @@ class Api(ApiTemplate):
90 slice_para = json.loads(image_service.slice_scheme) 88 slice_para = json.loads(image_service.slice_scheme)
91 extent = SliceScheme.get_polygon(slice_para, self.level, self.row, self.col) 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 im_data = self.create_by_opencv(image_type, pixel_array, quality) 160 im_data = self.create_by_opencv(image_type, pixel_array, quality)
133 -  
134 return Response(im_data, mimetype=image_type.lower()) 161 return Response(im_data, mimetype=image_type.lower())
135 162
136 except Exception as e: 163 except Exception as e:
@@ -139,8 +166,7 @@ class Api(ApiTemplate): @@ -139,8 +166,7 @@ class Api(ApiTemplate):
139 result["message"] = e.__str__() 166 result["message"] = e.__str__()
140 return result 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 :param xysize: 172 :param xysize:
@@ -152,28 +178,43 @@ class Api(ApiTemplate): @@ -152,28 +178,43 @@ class Api(ApiTemplate):
152 x = xysize[0] 178 x = xysize[0]
153 y = xysize[1] 179 y = xysize[1]
154 level = -1 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 pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / ( 187 pixel = x * y * (((extent[2] - extent[0]) * (extent[3] - extent[1])) / (
161 (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1]))) 188 (origin_extent[2] - origin_extent[0]) * (origin_extent[3] - origin_extent[1])))
162 return level 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 if image_type.__eq__("image/jpeg") or image_type.__eq__("image/jpg"): 193 if image_type.__eq__("image/jpeg") or image_type.__eq__("image/jpg"):
167 r, buf = cv2.imencode(".jpg", pixel_array, [cv2.IMWRITE_JPEG_QUALITY, quality]) 194 r, buf = cv2.imencode(".jpg", pixel_array, [cv2.IMWRITE_JPEG_QUALITY, quality])
168 image_out = buf.tobytes() 195 image_out = buf.tobytes()
169 else: 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 four[pixel_array[:, :, 0] == 65536] = 0 199 four[pixel_array[:, :, 0] == 65536] = 0
172 r, buf = cv2.imencode(".png", numpy.dstack((pixel_array, four))) 200 r, buf = cv2.imencode(".png", numpy.dstack((pixel_array, four)))
173 image_out = buf.tobytes() 201 image_out = buf.tobytes()
174 return image_out 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 通过RPC获取远程数据 219 通过RPC获取远程数据
179 :param image: 220 :param image:
@@ -181,24 +222,21 @@ class Api(ApiTemplate): @@ -181,24 +222,21 @@ class Api(ApiTemplate):
181 :param bands: 222 :param bands:
182 :return: 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 t1 = time.time() 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 data = gzip.decompress(data) 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 return data 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 :param image: 242 :param image:
@@ -206,7 +244,7 @@ class Api(ApiTemplate): @@ -206,7 +244,7 @@ class Api(ApiTemplate):
206 :param bands: 244 :param bands:
207 :return: 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 ceng = 0 248 ceng = 0
211 img: Dataset = gdal.Open(image.path, 0) 249 img: Dataset = gdal.Open(image.path, 0)
212 t1 = time.time() 250 t1 = time.time()
@@ -214,14 +252,16 @@ class Api(ApiTemplate): @@ -214,14 +252,16 @@ class Api(ApiTemplate):
214 252
215 # 自决定金字塔等级 253 # 自决定金字塔等级
216 xysize = [img.RasterXSize, img.RasterYSize] 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 band_data: Band = img.GetRasterBand(band) 257 band_data: Band = img.GetRasterBand(band)
  258 +
219 max_level = band_data.GetOverviewCount() 259 max_level = band_data.GetOverviewCount()
220 260
221 # 超出空间范围 261 # 超出空间范围
222 if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[ 262 if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[
223 3] or extent[3] < origin_extent[1]: 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 else: 266 else:
227 image_level = self.determine_level(xysize, origin_extent, extent, max_level) 267 image_level = self.determine_level(xysize, origin_extent, extent, max_level)
@@ -253,7 +293,7 @@ class Api(ApiTemplate): @@ -253,7 +293,7 @@ class Api(ApiTemplate):
253 293
254 y_g = math.ceil((extent[3] - extent[1]) / grid_y) 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,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 out_off_x = int(math.ceil((inter_extent[0] - extent[0]) / out_grid_x)) 322 out_off_x = int(math.ceil((inter_extent[0] - extent[0]) / out_grid_x))
283 out_off_y = int(math.ceil((extent[3] - inter_extent[3]) / out_grid_y)) 323 out_off_y = int(math.ceil((extent[3] - inter_extent[3]) / out_grid_y))
@@ -290,7 +330,7 @@ class Api(ApiTemplate): @@ -290,7 +330,7 @@ class Api(ApiTemplate):
290 overview_raster: ndarray = overview.ReadAsArray(off_x, off_y, x_g, y_g, out_x_g, 330 overview_raster: ndarray = overview.ReadAsArray(off_x, off_y, x_g, y_g, out_x_g,
291 out_y_g) 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 dat[out_off_y:out_off_y + out_y_g, out_off_x:out_off_x + out_x_g] = overview_raster 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 empty = dat 336 empty = dat
@@ -299,11 +339,43 @@ class Api(ApiTemplate): @@ -299,11 +339,43 @@ class Api(ApiTemplate):
299 ceng += 1 339 ceng += 1
300 return pixel_array 340 return pixel_array
301 341
302 - def determin_intersect(self,extent1,extent2): 342 + def determin_intersect(self, extent1, extent2):
303 g1 = GeometryAdapter.envelop_2_polygon(extent1) 343 g1 = GeometryAdapter.envelop_2_polygon(extent1)
304 g2 = GeometryAdapter.envelop_2_polygon(extent2) 344 g2 = GeometryAdapter.envelop_2_polygon(extent2)
305 return g1.Intersect(g2) 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 class MyThread(Thread): 380 class MyThread(Thread):
309 def __init__(self,func,args=()): 381 def __init__(self,func,args=()):
@@ -318,18 +390,5 @@ class MyThread(Thread): @@ -318,18 +390,5 @@ class MyThread(Thread):
318 except Exception: 390 except Exception:
319 return None 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,7 +4,7 @@
4 #email: nheweijun@sina.com 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 from app.models import db 8 from app.models import db
9 9
10 10
@@ -16,21 +16,31 @@ class Image(db.Model): @@ -16,21 +16,31 @@ class Image(db.Model):
16 __tablename__ = 'dmdms_image' 16 __tablename__ = 'dmdms_image'
17 guid = Column(String(256), primary_key=True) 17 guid = Column(String(256), primary_key=True)
18 name = Column(String) 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 raster_x_size = Column(Integer) 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 null_value = Column(Integer) 25 null_value = Column(Integer)
25 available = Column(Integer)#影像是否可用,不可用可能在创建金字塔中 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 #坐标wkt 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 dmdms_image_rel = db.Table('dmdms_image_rel', 45 dmdms_image_rel = db.Table('dmdms_image_rel',
36 Column('image_guid',String, ForeignKey('dmdms_image.guid')), 46 Column('image_guid',String, ForeignKey('dmdms_image.guid')),
@@ -53,12 +63,34 @@ class ImageService(db.Model): @@ -53,12 +63,34 @@ class ImageService(db.Model):
53 description = Column(Text) 63 description = Column(Text)
54 slice_scheme = Column(Text) 64 slice_scheme = Column(Text)
55 extent = Column(String(256)) 65 extent = Column(String(256))
  66 + node = Column(Integer)
56 #可视范围geojson 67 #可视范围geojson
57 visual_range = Column(Text) 68 visual_range = Column(Text)
58 #影像服务缩略图 69 #影像服务缩略图
59 overview = Column(Binary) 70 overview = Column(Binary)
  71 +
60 images = db.relationship('Image', 72 images = db.relationship('Image',
61 secondary=dmdms_image_rel, 73 secondary=dmdms_image_rel,
62 backref='image_services', 74 backref='image_services',
63 lazy='dynamic' 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,11 +51,10 @@ class Api(ApiTemplate):
51 data = self.download_gdb(table_names, ds,database_guid) 51 data = self.download_gdb(table_names, ds,database_guid)
52 52
53 result["data"] = data 53 result["data"] = data
54 - result["state"] = 1 54 + result["result"] = True
55 except Exception as e: 55 except Exception as e:
56 - print(traceback.format_exc())  
57 - result["message"]= e.__str__()  
58 - result["state"]=-1 56 + raise e
  57 +
59 finally: 58 finally:
60 if ds: 59 if ds:
61 ds.Destroy() 60 ds.Destroy()
@@ -225,7 +225,8 @@ class EntryDataVacuate: @@ -225,7 +225,8 @@ class EntryDataVacuate:
225 if geo is not None: 225 if geo is not None:
226 out_geom:Geometry = GeometryAdapter.change_geom(geo, geom_type) 226 out_geom:Geometry = GeometryAdapter.change_geom(geo, geom_type)
227 out_feature.SetGeometry(out_geom) 227 out_feature.SetGeometry(out_geom)
228 - 228 + # 出现fid为0经常有问题
  229 + out_feature.SetFID(out_feature.GetFID() + 1)
229 pg_layer.CreateFeature(out_feature) 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()
1 # coding=utf-8 1 # coding=utf-8
2 2
3 # 程序部署ip:host 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 # 指定精华表所在位置(必须为空间库),设置为None则存放在各自的实体库中 9 # 指定精华表所在位置(必须为空间库),设置为None则存放在各自的实体库中
10 VACUATE_DB_URI = None 10 VACUATE_DB_URI = None
@@ -359,6 +359,7 @@ WSGIDaemonProcess dmapmanager processes=4 threads=16 display-name=%{GROUP} @@ -359,6 +359,7 @@ WSGIDaemonProcess dmapmanager processes=4 threads=16 display-name=%{GROUP}
359 dmapmanager 359 dmapmanager
360 #Authorization请求头顺利转发 360 #Authorization请求头顺利转发
361 On 361 On
  362 + %{GLOBAL}
362 363
363 / /usr/src/app/run.wsgi 364 / /usr/src/app/run.wsgi
364 <Directory /usr/> 365 <Directory /usr/>
@@ -24,7 +24,7 @@ fi @@ -24,7 +24,7 @@ fi
24 #启动容器和apache 24 #启动容器和apache
25 echo "正在启动容器..." 25 echo "正在启动容器..."
26 set="--privileged=true -e TZ="Asia/Shanghai" --restart=always -e ALLOW_IP_RANGE=0.0.0.0/0" 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 docker exec -d dmapmanager systemctl start httpd 28 docker exec -d dmapmanager systemctl start httpd
29 sleep 5 29 sleep 5
30 curl localhost:$port/release 30 curl localhost:$port/release
@@ -18,6 +18,5 @@ import json @@ -18,6 +18,5 @@ import json
18 # 18 #
19 # print(sys.getsizeof(json.dumps(pixel_array.tolist()))) 19 # print(sys.getsizeof(json.dumps(pixel_array.tolist())))
20 # print(sys.getsizeof((content))) 20 # print(sys.getsizeof((content)))
21 -  
22 -for x in range(-3,3,1):  
23 - print(x)  
  21 +import random
  22 +print(int(random.random()*2))
  1 +#2021.09.10 Version:4.0.0
注册登录 后发表评论