image_wms.py 11.4 KB
# coding=utf-8
#author:        4N
#createtime:    2021/3/24
#email:         nheweijun@sina.com

from app.util import *
import traceback
import numpy
from flask import Response
import random
from app.modules.service.image.models import ImageService
from app.util.component.ApiTemplate import ApiTemplate
from app.util.component.ParameterUtil import ParameterUtil
import json
from threading import Thread
from .util.ImageData import ImageData
from .util.Cache import Cache
from .util.Opencv import Opencv

class Api(ApiTemplate):

    api_name = "WMS"

    def process(self):


        result = {}
        parameter: dict = self.para

        try:

            parameter = ParameterUtil.to_lower(parameter)
            self.guid = parameter.get("guid")
            bbox = parameter.get("bbox")
            width = int(parameter.get("width")) if parameter.get("width") else 256
            height = int(parameter.get("height")) if parameter.get("height") else 256
            image_type = parameter.get("format") if parameter.get("format") else "image/png"
            quality = int(parameter.get("quality")) if parameter.get("quality") else 30

            image_service_info, zoo, servers = Cache.cache_data(self.guid)

            re = parameter.get("request")
            if re and re.__eq__("GetCapabilities"):
                return self.get_capabilities(image_service_info["service"])


            # bands = [1, 2, 3]

            extent = [float(x) for x in bbox.split(",")]

            intersect_image = [im for im in image_service_info["images"] if self.determin_intersect(json.loads(im.extent),extent)]

            if len(intersect_image)>1:

                # 结果矩阵
                empty_list = [numpy.zeros((height,width), dtype=int) + 65536,
                              numpy.zeros((height,width), dtype=int) + 65536,
                              numpy.zeros((height,width), dtype=int) + 65536]

                pixel_array = numpy.zeros((height,width,3), dtype=int)
                thread_list = []

                for image in intersect_image:
                    #该影像的服务器,随机选取一个
                    image_servers = image.server.split(",")
                    image_servers = [ser for ser in image_servers if ser in servers]
                    if len(image_servers)>0:
                        indx = int(random.random() * len(image_servers))
                        image_server = image_servers[indx]
                    else:
                        image_server = "None"
                    bands = json.loads(image.band_view)

                    image_data = ImageData(image_server, image)

                    thread: MyThread = MyThread(image_data.get_data, args=(extent,bands,height,width))
                    thread.start()
                    thread_list.append(thread)


                for thread in thread_list:
                    thread.join()
                    data = thread.get_result()

                    # 掩膜在中央接口生成,合图
                    mask = numpy.zeros((height,width), dtype=int)
                    mask2 = numpy.zeros((height,width), dtype=int)
                    jizhun = data[:, :, 0]
                    mask[jizhun == 65536] = 1
                    mask[jizhun != 65536] = 0
                    mask2[jizhun == 65536] = 0
                    mask2[jizhun != 65536] = 1
                    # 掩膜计算
                    for i, d in enumerate(empty_list):
                        empty_list[i] = empty_list[i] * mask + data[:, :, i] * mask2

                for ii in [0, 1, 2]:
                    # opencv 颜色排序为GBR
                    pixel_array[:, :, 2 - ii] = empty_list[ii]


            elif len(intersect_image)==1:
                # 该影像的服务器,随机选取一个
                image = intersect_image[0]
                image_servers = image.server.split(",")
                image_servers = [ser for ser in image_servers if ser in servers]
                if len(image_servers) > 0:
                    indx = int(random.random() * len(image_servers))
                    image_server = image_servers[indx]
                else:
                    image_server = "None"

                bands = json.loads(image.band_view)

                image_data = ImageData(image_server, image)

                pixel_array_t = image_data.get_data(extent,bands,height,width)

                pixel_array = numpy.zeros((height, width, 3), dtype=int)
                for ii in [0, 1, 2]:
                    # opencv 颜色排序为GBR
                    pixel_array[:, :, 2 - ii] = pixel_array_t[:, :, ii]
            else:
                # 结果矩阵
                pixel_array = numpy.zeros((height, width, 3), dtype=int)+65536

            # 将图片生成在内存中,然后直接返回response
            im_data = Opencv.create_image(image_type, pixel_array, quality)

            if self.para.get("overview"):
                return pixel_array
            return Response(im_data, mimetype=image_type.lower())

        except Exception as e:
            print(traceback.format_exc())
            result["state"] = -1
            result["message"] = e.__str__()
            return result



    def determin_intersect(self, extent1, extent2):
        if extent2[2] < extent1[0] or extent2[0] > extent1[2] or extent2[1] > extent1[
            3] or extent2[3] < extent1[1]:
            return False
        else:
            return True

    def get_capabilities(self,image_service:ImageService):

        xml = '''<?xml version="1.0" encoding="utf-8" ?>
        <WMS_Capabilities version="1.2.0">
            <Service>
                <Name>WMS</Name>
                <Title>{service_title}</Title>
                <Abstract>{abstract}</Abstract>
                <Keywords>GIMS</Keywords>
                <OnlineResource/>
                <Fees>none</Fees>
                <AccessConstraints>none</AccessConstraints>
            </Service>
            <Capability>
                <Request>
                    <GetCapabilities>
                        <Format>text/xml</Format>
                        <DCPType>
                            <HTTP>
                                <Get>
                                    <OnlineResource xlink:href="{url}" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink"/>
                                </Get>
                            </HTTP>
                        </DCPType>
                    </GetCapabilities>
                    <GetMap>
                        <Format>png</Format>
                        <Format>jpeg</Format>
                        <Format>gif</Format>
                        <Format>image/png</Format>
                        <Format>image/jpeg</Format>
                        <Format>image/gif</Format>
                        <DCPType>
                            <HTTP>
                                <Get>
                                    <OnlineResource xlink:href="{url}" xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink"/>
                                </Get>
                            </HTTP>
                        </DCPType>
                    </GetMap>
                    <Map>
                        <Format>
                            <PNG/>
                            <GIF/>
                            <JPG/>
                        </Format>
                        <DCPType>
                            <HTTP>
                                <Get onlineResource="{url}"/>
                            </HTTP>
                        </DCPType>
                    </Map>
                    <Capabilities>
                        <Format>
                            <WMS_XML/>
                        </Format>
                        <DCPType>
                            <HTTP>
                                <Get onlineResource="{url}"/>
                            </HTTP>
                        </DCPType>
                    </Capabilities>
                    <FeatureInfo>
                        <Format>
                            <XML/>
                            <MIME/>
                        </Format>
                        <DCPType>
                            <HTTP>
                                <Get onlineResource="{url}"/>
                            </HTTP>
                        </DCPType>
                    </FeatureInfo>
                </Request>
                <Exception>
                    <Format>
                        <WMS_XML/>
                        <INIMAGE/>
                        <BLANK/>
                    </Format>
                </Exception>
                <Layer>
                    <Name>{service_name}</Name>
                    <Title>{service_title}</Title>
                    <CRS>{crs}</CRS>
                    <BoundingBox CRS="{crs}" maxx="{maxx}" maxy="{maxy}" minx="{minx}" miny="{miny}"/>
                    
                    <Layer queryable="1">
                        <CRS>{crs}</CRS>
                        <Name>{layer_name}</Name>
                        <Title>{layer_title}</Title>
                        <BoundingBox CRS="{crs}" maxx="{maxx}" maxy="{maxy}" minx="{minx}" miny="{miny}"/>
                    </Layer>
                </Layer>
            </Capability>
        </WMS_Capabilities>'''

        extent = json.loads(image_service.extent)
        xml = xml.format(service_title=image_service.name,
                         service_name=image_service.name,
                         abstract= "None" ,
                         crs="ESPG:4326",
                         layer_name=image_service.name,
                         layer_title=image_service.name,
                         maxx=extent[2],
                         maxy = extent[3],
                         minx = extent[0],
                         miny = extent[1],
                         url="http://{}/API/Service/Image/WMS?guid={}".format(configure.deploy_ip_host,image_service.guid))


        r = Response(response=xml, status=200, mimetype="application/xml")
        r.headers["Content-Type"] = "text/xml; charset=utf-8"
        return r

    api_doc = {
        "tags": ["影像接口"],
        "parameters": [
            {"name": "guid",
             "in": "query",
             "type": "string"},
            {"name": "bbox",
             "in": "query",
             "type": "string"},
            {"name": "width",
             "in": "query",
             "type": "string"},
            {"name": "height",
             "in": "query",
             "type": "string"},
            {"name": "format",
             "in": "query",
             "type": "string"},
            {"name": "quality",
             "in": "query",
             "type": "string"}
        ],
        "responses": {
            200: {
                "schema": {
                    "properties": {
                    }
                }
            }
        }
    }

class MyThread(Thread):
    def __init__(self,func,args=()):
        super(MyThread,self).__init__()
        self.func = func
        self.args = args
    def run(self):
        self.result = self.func(*self.args)
    def get_result(self):
        try:
            return self.result
        except Exception:
            return None