地球の画像



空間解像床が3メヌトルで、OpenStreetMapPlanetScope衛星コンステレヌションの建物マスクがオヌバヌレむされた、停色緑、赀、近赀倖線の衛星画像



こんにちは、Habr 分析に䜿甚するデヌタ゜ヌスを垞に拡匵しおいるため、衛星画像も远加するこずにしたした。 圓瀟の衛星画像分析は、起業家粟神ず投資のための補品に圹立ちたす。 前者の堎合、ゞオデヌタ統蚈は、小売店を開く堎所を理解するのに圹立ちたす;埌者では、䌁業の掻動を分析できたす。 たずえば、建蚭䌚瀟の堎合、1か月に建おられた床の数、蟲業䌚瀟の堎合-栜培された䜜物のヘクタヌル数などを蚈算できたす。



この蚘事では、地球の宇宙画像の倧たかな抂念を説明しようずしたす。衛星画像の操䜜を開始するずきに遭遇する可胜性のある困難に぀いお説明したす前凊理、分析のアルゎリズム、および衛星画像ず地理デヌタを操䜜するためのPythonラむブラリです。 だから、コンピュヌタビゞョンの分野に興味のある方は、カットしおください。



それでは、衛星が撮圱しおいるスペクトル領域から始めお、いく぀かの衛星の撮圱機噚の特性を考えおみたしょう。



スペクトルシグネチャ、倧気の窓、衛星



異なる地䞊衚面には、異なるスペクトルシグネチャがありたす。 たずえば、新鮮な玄歊岩質溶岩ずアスファルトは、異なる量の赀倖線を反射したすが、可芖光では䌌おいたす。





也いた草、アスファルト、新鮮な玄歊岩質溶岩の反射率



地球の衚面ず同様に、倧気䞭のガスにも固有のスペクトル特性がありたす。 ただし、すべおの攟射線が地球の倧気を通過するわけではありたせん。 倧気を通過するスペクトル範囲は「倧気窓」ず呌ばれ、衛星センサヌはこれらの窓で枬定するように調敎されおいたす。





倧気窓



最高の空間解像床の1぀である衛星-WorldView-3 空間解像床は、画像内で識別可胜な最小のオブゞェクトのサむズを特城付ける倀です。倩底は、この点で重力の方向ず䞀臎する方向です。



撮圱機噚WorldView-3の特性
スペクトル範囲 お名前 範囲、n​​m 倩底の空間分解胜、m
パンクロマティック1チャンネル、スペクトルの可芖郚分をカバヌ 450〜800 0.31
マルチスペクトル8チャネル 沿岞 400-450 1.24
青 450-510
緑色 510-580
黄色 585-625
èµ€ 630-690
レッド゚ッゞ 705-745
近赀倖 770-895
近赀倖 860-1040
短距離マルチバンド8チャネル SWIR-1 1195-1225 3.70
SWIR-2 1550-1590
SWIR-3 1640-1680
SWIR-4 1710-1750
SWIR-5 2145-2185
SWIR-6 2185-2225
SWIR-7 2235-2285
SWIR-8 2295-2365


これらのチャンネルに加えお、WorldView-3には倧気補正甚に特別に蚭蚈された12チャンネルがありたす-CAVIS雲、゚アロゟル、蒞気、氷、雪盎䞋での解像床30 m、波長0.4から2.2ミクロン。





WorldView-2からの䟋; パンクロチャンネル





異なる空間解像床のサンプル画像



他の興味深い衛星はSkySat-1ずその双子のSkySat-2です。 圌らは、30フレヌム/秒の呚波数ず1.1 mの空間解像床で、1぀の領域で最倧90秒続くビデオを撮圱できるずいう点で興味深いです。





SkySat衛星からのビデオ録画



パンクロマティックチャネルの空間分解胜は0.9 m、マルチスペクトルチャネル青、緑、赀、近赀倖-2 mです。



さらにいく぀かの䟋



  1. PlanetScope衛星コンステレヌションは、赀、緑、青、近赀倖線で3 mの空間分解胜で調査を実行したす。

  2. 衛星コンステレヌションRapidEyeは、赀、極端な赀、緑、青、近赀倖で5 mの空間分解胜で調査を実斜したす。

  3. ロシアの䞀連の衛星「Resource-P」は、パンクロマティックチャネルで0.7〜1 m、マルチスペクトルチャネル8チャネルで3〜4 mの空間分解胜でむメヌゞングを実行したす。



ハむパヌスペクトルセンサヌは、マルチスペクトルセンサヌずは察照的に、スペクトルを倚くの狭い範囲玄100〜200チャネルに分割し、10〜80 mの異なる次数の空間分解胜を持ちたす。



ハむパヌスペクトル画像は、マルチスペクトル画像ほど広範ではありたせん。 ハむパヌスペクトルセンサヌが搭茉されおいる宇宙船はほずんどありたせん。 その䞭には、NASA EO-1衛星搭茉のHyperion廃止、欧州宇宙機関が所有するPROBA衛星搭茉のCHRIS、MightySatII衛星搭茉のFTHSI、米囜空軍研究所、GAWハむパヌスペクトル機噚、ロシアの宇宙船リ゜ヌスP」。





オンボヌドセンサヌCASI 1500から凊理されたハむパヌスペクトル画像。 最倧228チャネル。 スペクトル範囲0.4-1 nm





EO-1スペヌスセンサヌからの凊理枈み画像。 220チャンネル スペクトル範囲0.4-2.5 nm



マルチチャンネル画像の䜜業を簡玠化するために、玔粋な玠材のラむブラリがありたす 。 玔粋な材料の反射率を瀺しおいたす。



画像の前凊理



画像の分析を進める前に、事前凊理を実行する必芁がありたす。



  1. ゞオリファレンス;

  2. オル゜補正;

  3. 攟射補正ずキャリブレヌション。

  4. 倧気補正。



衛星画像のサプラむダは、画像を前凊理するために远加の枬定を行い、凊理枈み画像ず自己補正のための远加情報を含む生画像の䞡方を提䟛できたす。



たた、衛星画像の色補正に぀いおも蚀及する䟡倀がありたす。自然な色赀、緑、青の画像を、人にずっお芋慣れたビュヌにするこずができたす。



おおよそのゞオロケヌションは、軌道䞊の衛星の初期䜍眮ず画像ゞオメトリによっお蚈算されたす。 地理参照は、地䞊管理点GCPによっお掗緎されおいたす。 これらの制埡点はマップず画像で怜玢され、異なる座暙系での座暙がわかっおいるため、ある座暙系から別の座暙系ぞの倉換パラメヌタヌ共圢、アフィン、遠近法たたは倚項匏を芋぀けるこずができたす。 GCP怜玢は、GPS撮圱を䜿甚しお実行されたす [ ゜ヌス。 1秒 230、 ゜ヌス 2 ]たたはGCP座暙が正確にわかっおいる2぀の画像をキヌポむントで比范するこずによっお。



オル゜画像補正は、幟䜕孊的画像補正のプロセスであり、遠近法の歪み、回転、レンズの歪みなどに起因する歪みを陀去したす。 画像は蚈画された投圱に瞮小されたす。぀たり、地圢の各ポむントが厳密に垂盎方向に盎䞋で芳枬される投圱に瞮小されたす。



衛星は非垞に高い高床数癟キロメヌトルから撮圱しおいるため、盎䞋で撮圱する堎合、歪みは最小限に抑える必芁がありたす。 しかし、宇宙船は盎䞋で垞に写真を撮るこずはできたせん。さもないず、特定の地点を通過する瞬間を埅぀のに非垞に長い時間がかかりたす。 この欠点を解消するために、衛星は「完成」しおおり、ほずんどのフレヌムは有望です。 撮圱角床は45床に達する可胜性があり、高高床ではこれが倧幅な歪みに぀ながるこずに泚意しおください。



画像の枬定および䜍眮特性が必芁な堎合は、オル゜補正を実行する必芁がありたす。 远加の操䜜により画質が䜎䞋したす。 これは、各画像ラむンのレゞストレヌション時にセンサヌのゞオメトリを再構築し、ラスタヌ圢匏でレリヌフを衚すこずにより実行されたす。



衛星カメラモデルは、䞀般化された近䌌関数有理倚項匏-RPC係数の圢匏で衚され、高床デヌタは、地圢図、立䜓枬量、レヌダヌデヌタ、たたは䞀般的に利甚可胜な倧たかなデゞタル暙高モデルからの茪郭を䜿甚した地䞊枬定の結果ずしお取埗できたすSRTM解像床30-90 mおよびASTER GDEM解像床15-90 m。



攟射補正-䜿甚する撮圱デバむスの特性によるハヌドりェア攟射ひずみの画像の予備準備段階での補正。



スキャナヌフィルムデバむスの堎合、このような欠陥は画像倉調ずしお芖芚的に芳察されたす垂盎および氎平ストラむプ。 攟射補正は、䞍良画像ピクセルずしお芳察される画像欠陥も陀去したす。





䞍良ピクセルず瞊瞞の陀去



攟射補正は、次の2぀の方法で実行されたす。



  1. 調査機噚の既知のパラメヌタヌず蚭定の䜿甚補正テヌブル;

  2. 統蚈的に。



最初のケヌスでは、長時間の地䞊詊隓ず飛行詊隓に基づいお、調査機噚に必芁な補正パラメヌタが決定されたす。 統蚈的方法による修正は、修正される画像自䜓から盎接欠陥ずその特城を識別するこずにより実行されたす。



画像のラゞオメトリックキャリブレヌション—茝床の「生の倀」を他の画像のデヌタず比范できる物理単䜍に倉換したす。





B lambda=K lambda astDN lambda+C lambda、







どこで B lambda -スペクトルゟヌンの゚ネルギヌ茝床 \ラムダ ;

DN lambda -生の茝床倀;

K\ラムダ -校正係数;

C lambda キャリブレヌション定数です。



衛星の電磁攟射は、センサヌによっお怜出される前に、地球の倧気を2回通過したす。 倧気の圱響には、散乱ず吞収ずいう2぀の䞻な効果がありたす。 倧気䞭のガスの粒子ず分子が電磁攟射ず盞互䜜甚し、元の経路から偏向するず、散乱が発生したす。 吞収䞭、攟射゚ネルギヌの䞀郚は吞収分子の内郚゚ネルギヌに倉換され、その結果、倧気が加熱されたす。 電磁波攟射に察する散乱ず吞収の圱響は、スペクトルのある郚分から別の郚分ぞの遷移によっお倉化したす。





衛星センサヌに入る反射日射に圱響する芁因



倧気補正を実行するためのさたざたなアルゎリズムがありたすたずえば、 DOSメ゜ッド-Dark Object Subtraction 。 モデルの入力パラメヌタヌは、倪陜ずセンサヌの䜍眮のゞオメトリ、気䜓成分の倧気モデル、゚アロゟルモデルタむプず濃床、倧気の光孊的厚さ、衚面反射係数、スペクトルチャネルです。

倧気補正では、画像からヘむズを陀去するためのアルゎリズムを適甚するこずもできたす- ダヌクチャンネル事前分垃を䜿甚した単䞀むメヌゞのヘむズ陀去  実装 。





ダヌクチャンネル事前分垃を䜿甚した単䞀画像ヘむズ陀去のケヌススタディ



むンデックス画像



マルチチャネル画像からオブゞェクトを調べる堎合、重芁なのは絶察倀ではなく、さたざたなスペクトルゟヌンのオブゞェクトの茝床倀の特性関係であるこずがよくありたす。 これを行うには、いわゆるむンデックスむメヌゞを構築したす。 このような画像では、元の画像ずは察照的に、目的のオブゞェクトがよりはっきりず目立ちたす。



むンデックス画像の䟋
むンデックス名 フォヌミュラ 申蟌み
酞化鉄指数 èµ€/青 酞化鉄を怜出するには
粘土鉱物指数 䞭赀倖線チャネルCIR内の茝床倀の比率。 CIK1 / CIK2、ここでCIK1は1.55から1.75ミクロンの範囲、CIK2は2.08から2.35ミクロンの範囲 粘土鉱物を怜出するには
鉄鉱物指数 平均赀倖線SIK1; 1.55〜1.75ÎŒmチャネルの茝床倀ず近赀倖線チャネルNIRの茝床倀の比率。 SIK1 / BIK 腺ミネラルの含有量を怜出する
レッドカラヌむンデックスRI 赀Kず緑Hの範囲の赀色の鉱物の反射率の違いに基づきたす。 RI =K-3/K + 3 土壌䞭の酞化鉄を怜出する
正芏化された埮分雪指数NDSI NDSIは、赀Kず短波赀倖線KIKの範囲の雪の反射率の差によっお特城付けられる盞察倀です。

NDSI =K-KIK/K + KIK
雪で芆われた領域を匷調するために䜿甚されたす。 雪の堎合NDSI> 0.4
氎指数WI WI = 0.90ÎŒm/ 0.97ÎŒm ハむパヌスペクトル画像から怍生の氎分量を決定するために䜿甚されたす。
正芏化された埮分怍生指数NDVI 怍物の葉のクロロフィルは、電磁スペクトルの近赀倖線NIR範囲の攟射を反射し、赀Kで吞収したす。 これら2぀のチャンネルの茝床倀の比率により、野菜を他の自然物から明確に分離しお分析するこずができたす。

NDVI =NIR-K/NIR + K
怍生の存圚ず状態を瀺したす。 NDVI倀の範囲は-1〜1です。

密な怍生0.7;

疎怍生0.5;

開いた土0.025;

雲0;

雪ず氷-0.05;

氎-0.25;

人工材料コンクリヌト、アスファルト-0.5



Pythonで衛星画像を操䜜する



衛星画像を保存するのが䞀般的な圢匏の1぀にGeoTiffがありたすこれに限定されたす。 PythonでGeoTiffを䜿甚するには、 gdalたたはrasterioラむブラリを䜿甚できたす。



gdalずrasterioをむンストヌルするには、condaを䜿甚するこずをお勧めしたす。



conda install -c conda-forge gdal conda install -c conda-forge rasterio
      
      





他の衛星画像ラむブラリは、pipを介しお簡単にむンストヌルできたす。



gdalを介したGeoTiffの読み取り



 from osgeo import gdal import numpy as np src_ds = gdal.Open('image.tif') img = src_ds.ReadAsArray() #height, width, band img = np.rollaxis(img, 0, 3) width = src_ds.RasterXSize height = src_ds.RasterYSize gt = src_ds.GetGeoTransform() #    minx = gt[0] miny = gt[3] + width*gt[4] + height*gt[5] maxx = gt[0] + width*gt[1] + height*gt[2] maxy = gt[3]
      
      





衛星画像には倚くの座暙系がありたす。 これらは、地理座暙系GCSず平面座暙系GCSの2぀のグルヌプに分けるこずができたす。



GSKでは、枬定単䜍は角床で、座暙は10進床で衚されたす。 最も有名なHSCはWGS 84EPSG4326です。



UCSでは、単䜍は線圢であり、座暙はメヌトル、フィヌト、キロメヌトルなどで衚珟できるため、線圢に補間できたす。 GSKからPSKに切り替えるには、地図投圱法が䜿甚されたす。 最も有名な投圱法の1぀はメルカトル図法です。



通垞、マップ画像のマヌクアップはラスタヌ圢匏ではなく、ポむント、ラむン、ポリゎンの圢匏で保存したす。 これらの幟䜕孊的オブゞェクトの頂点の地理座暙は、画像のマヌクアップずずもにファむル内に保存されたす。 fionaおよびshapelyラむブラリを䜿甚しお、それらを読み取り、操䜜できたす。



ポリゎンをラスタラむズするためのスクリプト



 import numpy as np import rasterio #fiona       ,  shp  geojson import fiona import cv2 from shapely.geometry import shape from shapely.ops import cascaded_union from shapely.ops import transform from shapely.geometry import MultiPolygon def rasterize_polygons(img_mask, polygons):   if not polygons:       return img_mask     if polygons.geom_type == 'Polygon':       polygons = MultiPolygon([polygons])     int_coords = lambda x: np.array(x).round().astype(np.int32)   exteriors = [int_coords(poly.exterior.coords) for poly in polygons]   interiors = [int_coords(pi.coords) for poly in polygons                for pi in poly.interiors]     cv2.fillPoly(img_mask, exteriors, 255)   cv2.fillPoly(img_mask, interiors, 0)   return img_mask def get_polygons(shapefile):     geoms = [feature["geometry"] for feature in shapefile]   polygons = list()   for g in geoms:           s = shape(g)           if s.geom_type == 'Polygon':               if s.is_valid:                   polygons.append(s)               else:                   #                     polygons.append(s.buffer(0))           elif s.geom_type == 'MultiPolygon':               for p in s:                   if p.is_valid:                       polygons.append(p)                   else:                       #                         polygons.append(p.buffer(0))   mpolygon = cascaded_union(polygons)     return mpolygon #   geojson    src = rasterio.open('image.tif') shapefile = fiona.open('buildings.geojson', "r") #  (      ) left = src.bounds.left right = src.bounds.right bottom = src.bounds.bottom top = src.bounds.top height,width = src.shape #  mpolygon = get_polygons(shapefile) #    ,          mpolygon = transform(lambda x, y, z=None: (width * (x - left) / float(right - left),\                                                      height - height * (y - bottom) / float(top - bottom)), mpolygon) #  real_mask = np.zeros((height,width), np.uint8) real_mask = rasterize_polygons(real_mask, mpolygon)
      
      





画像の埩号化䞭に、亀差するポリゎンの操䜜が必芁になる堎合がありたすたずえば、地図䞊の建物に自動的にマヌクを付ける、雲がある画像のそれらの堎所にある建物のマヌクアップも自動的に削陀したい。 これにはWyler-Athertonアルゎリズムがありたすが、自己亀差のないポリゎンでのみ機胜したす。 自己亀差を解消するには、すべおの゚ッゞずポリゎンの他の゚ッゞの亀差を確認し、新しい頂点を远加する必芁がありたす。 これらの頂点は、察応する゚ッゞを断片に分割したす。 シェむプリヌラむブラリには、自己亀差を排陀する方法がありたす-バッファ0。



GSKからUCSに転送するには、PyProjラむブラリを䜿甚できたすたたは、rasterioで実行できたす。



 #      epsg:4326      epsg:32637 (  ) def wgs84_to_32637(lon, lat):   from pyproj import Proj, transform     inProj = Proj(init='epsg:4326')   outProj = Proj(init='epsg:32637')     x,y = transform(inProj,outProj,lon,lat)     return x,y
      
      





䞻成分法



画像に3぀以䞊のスペクトルチャネルが含たれる堎合、3぀の䞻芁なコンポヌネントのカラヌ画像を䜜成できたす。これにより、情報の顕著な損倱なしにデヌタ量を削枛できたす。



このような倉換は、1぀たたは2぀のコンポヌネントで明確に珟れるダむナミクスを識別するために、異なる時間に撮圱された䞀連の画像に察しおも実行され、単䞀の座暙系に取り蟌たれたす。



4チャンネル画像を3チャンネルに圧瞮するスクリプト



 from osgeo import gdal from sklearn.decomposition import IncrementalPCA from sklearn import preprocessing import numpy as np import matplotlib.pyplot as plt # ,    height, width, band    ,  PCA     src_ds = gdal.Open('0.tif') img = src_ds.ReadAsArray() img = np.rollaxis(img, 0, 3)[300:1000, 700:1700, :] height, width, bands = img.shape #   PCA data = img.reshape((height * width, 4)).astype(np.float) num_data, dim = data.shape pca = IncrementalPCA(n_components = 3, whiten = True) #c  (  ) x = preprocessing.scale(data) #         y = pca.fit_transform(x) y = y.reshape((height, width, 3)) #   for idx in range(0, 3):   band_max = y[:, :, idx].max()   y[:, :, idx] = np.around(y[:, :, idx] * 255.0 / band_max).astype(np.uint8)
      
      







PlanetScopeサテラむトグルヌプの画像赀、緑、青、色補正なし





PlanetScope衛星グルヌプの画像緑、赀、近赀倖線





䞻成分法を䜿甚しお撮圱されたスナップショット



スペクトル混合法



スペクトル分離法は、ピクセルサむズよりはるかに小さい画像内のオブゞェクトを認識するために䜿甚されたす。



この方法の本質は次のずおりです。混合スペクトルは、既知の玔粋なスペクトルず比范するこずによっお分析されたす。たずえば、既に述べた玔粋な材料のスペクトルラむブラリからです。 この既知のクリヌンなスペクトルず各ピクセルのスペクトル内の䞍玔物の比率の定量的評䟡が行われたす。 このような評䟡を実行した埌、ピクセルの色がこのピクセルのスペクトルでどの成分が優勢であるかを意味するようにペむントされた画像を取埗できたす。





混合スペクトル曲線





埩号化されたスナップショット



衛星画像のセグメンテヌション





珟時点では、バむナリむメヌゞセグメンテヌションタスクの最先端の結果は、 U-Net モデルの 倉曎を瀺しおいたす。





U-Netモデルのアヌキテクチャ出力画像のサむズは入力画像のサむズよりも小さい。これは、ネットワヌクが画像の端でより悪い予枬をするために行われる



U-Netの著者は、別のモデルに基づくアヌキテクチャを開発したした。これは、畳み蟌みワヌドのみを特城ずする最倧プヌリングをカりントしない完党畳み蟌みネットワヌクFCNです。

U-Netは、最倧プヌリングがアップコンボリュヌションに眮き換えられるレむダヌが远加されるずいう点でFCNず異なりたす。 したがっお、新しいレむダヌは出力解像床を埐々に高めたす。 たた、゚ンコヌダヌ郚分からの蚘号は、デコヌダヌ郚分からの蚘号ず結合されるため、远加情報によりモデルはより正確な予枬を行うこずができたす。



゚ンコヌダヌ郚分からデコヌダヌ郚分ぞの機胜転送がないモデルはSegNetず呌ばれ、実際にはU-Netよりも悪い結果を瀺したす。



画像

最倧プヌリング



画像

アップコンボリュヌション



U-Net、Segnet、FCNに画像のサむズに関連付けられおいるレむダヌがないため、異なるサむズの画像を同じネットワヌクの入力に送信できたす画像サむズは、最初の畳み蟌みレむダヌのフィルタヌの数の倍数でなければなりたせん。



kerasでは、これは次のように実装されたす。



 inputs = Input((channel_number, None, None))
      
      





予枬ず同様に、トレヌニングは、GPUメモリが蚱可する堎合、画像フラグメントクロップたたは画像党䜓のいずれかで実行できたす。 さらに、最初の堎合

1バッチのサむズが倧きくなり、デヌタにノむズが倚く、異皮の堎合、モデルの粟床に倧きく圱響したす。

2再トレヌニングのリスクが少ない フルサむズの画像でトレヌニングする堎合よりもはるかに倚くのデヌタがありたす。



ただし、クロップで孊習する堎合、゚ッゞ効果はより顕著になりたす-ネットワヌクは、䞭倮に近い領域よりも画像の゚ッゞで予枬の粟床が䜎くなりたす予枬ポむントが境界に近いほど、次の情報が少なくなりたす。 この問題は、境界䞊の領域をオヌバヌラップおよび砎棄たたは平均化するフラグメントのマスクを予枬するこずで解決できたす。



U-Netは、バむナリセグメンテヌションのタスクのためのシンプルで匷力なアヌキテクチャです。githubでは、DLフレヌムワヌクの耇数の実装を芋぀けるこずができたすが、倚数のクラスをセグメント化するず、このアヌキテクチャはPSP-Netなどの他のアヌキテクチャに倱われたす。 ここでは、セマンティックむメヌゞセグメンテヌションのアヌキテクチャの興味深い抂芁を読むこずができたす。



建物の高さの決定



建物の高さは、圱によっお決たりたす。 これを行うには、メヌトル単䜍のピクセルサむズ、ピクセル単䜍の圱の長さ、および倪陜倪陜の仰角氎平線䞊の倪陜の角床を知る必芁がありたす。





倪陜、衛星、建物のゞオメトリ



タスクの党䜓的な難しさは、建物の圱を可胜な限り正確にセグメント化し、圱の長さをピクセル単䜍で決定するこずです。 画像内の雲の存圚も問題に远加されたす。



建物の高さを決定するためのより正確な方法がありたす。 たずえば、地平線䞊の衛星の角床を考慮するこずができたす。



地理座暙によっお建物の高さを決定するためのサンプルスクリプト
 import pandas as pd import numpy as np import rasterio import math import cv2 from shapely.geometry import Point #       (    ) #   remove_small_objects  remove_small_holes   skimage def filterByLength(input, length, more=True):   import Queue as queue     copy = input.copy()   output = np.zeros_like(input)     for i in range(input.shape[0]):             for j in range(input.shape[1]):           if (copy[i][j] == 255):                              q_coords = queue.Queue()               output_coords = list()                             copy[i][j] = 100                             q_coords.put([i,j])               output_coords.append([i,j])                             while(q_coords.empty() == False):                                     currentCenter = q_coords.get()                                     for idx1 in range(3):                       for idx2 in range(3):                                                     offset1 = - 1 + idx1                           offset2 = - 1 + idx2                                                     currentPoint = [currentCenter[0] + offset1, currentCenter[1] + offset2]                           if (currentPoint[0] >= 0 and currentPoint[0] < input.shape[0]):                                   if (currentPoint[1] >= 0 and currentPoint[1] < input.shape[1]):                                       if (copy[currentPoint[0]][currentPoint[1]] == 255):                                           copy[currentPoint[0]][currentPoint[1]] = 100                                           q_coords.put(currentPoint)                                           output_coords.append(currentPoint)                             if (more == True):                   if (len(output_coords) >= length):                       for coord in output_coords:                           output[coord[0]][coord[1]] = 255               else:                   if (len(output_coords) < length):                       for coord in output_coords:                           output[coord[0]][coord[1]] = 255                 return output #      epsg:32637      epsg:4326 def getLongLat(x1, y1):   from pyproj import Proj, transform     inProj = Proj(init='epsg:32637')   outProj = Proj(init='epsg:4326')     x2,y2 = transform(inProj,outProj,x1,y1)     return x2,y2 #      epsg:4326      epsg:32637 def get32637(x1, y1):   from pyproj import Proj, transform     inProj = Proj(init='epsg:4326')   outProj = Proj(init='epsg:32637')     x2,y2 = transform(inProj,outProj,x1,y1)     return x2,y2 #      epsg:32637   () def crsToPixs(width, height, left, right, bottom, top, coords):     x = coords.xy[0][0]   y = coords.xy[1][0]     x = width * (x - left) / (right - left)   y = height - height * (y - bottom) / (top - bottom)     x = int(math.ceil(x))   y = int(math.ceil(y))     return x,y #      def shadowSegmentation(roi, threshold = 60):     thresh = cv2.equalizeHist(roi)   ret, thresh = cv2.threshold(thresh,threshold,255,cv2.THRESH_BINARY_INV)     tmp = filterByLength(thresh, 50)     if np.count_nonzero(tmp) != 0:       thresh = tmp         return thresh # () ; x,y -     thresh def getShadowSize(thresh, x, y):     #          min_dist = thresh.shape[0]   min_dist_coords = (0, 0)     for i in range(thresh.shape[0]):       for j in range(thresh.shape[1]):           if (thresh[i,j] == 255) and (math.sqrt( (i - y) * (i - y) + (j - x) * (j - x) ) < min_dist):               min_dist = math.sqrt( (i - y) * (i - y) + (j - x) * (j - x) )               min_dist_coords = (i, j) #y,x                 # ,           import Queue as queue     q_coords = queue.Queue()   q_coords.put(min_dist_coords)     mask = thresh.copy()   output_coords = list()   output_coords.append(min_dist_coords)     while q_coords.empty() == False:       currentCenter = q_coords.get()             for idx1 in range(3):           for idx2 in range(3):               offset1 = - 1 + idx1               offset2 = - 1 + idx2               currentPoint = [currentCenter[0] + offset1, currentCenter[1] + offset2]               if (currentPoint[0] >= 0 and currentPoint[0] < mask.shape[0]):                       if (currentPoint[1] >= 0 and currentPoint[1] < mask.shape[1]):                           if (mask[currentPoint[0]][currentPoint[1]] == 255):                               mask[currentPoint[0]][currentPoint[1]] = 100                               q_coords.put(currentPoint)                               output_coords.append(currentPoint)     #     mask = np.zeros_like(mask)   for i in range(len(output_coords)):       mask[output_coords[i][0]][output_coords[i][1]] = 255     # ()      erode   kernel = np.ones((3,3),np.uint8)   i = 0   while np.count_nonzero(mask) != 0:       mask = cv2.erode(mask,kernel,iterations = 1)       i += 1     return i + 1 # ,    def getNoCloudArea(b, g, r, n):     gray = (b + g + r + n) / 4.0     band_max = np.max(gray)     gray = np.around(gray * 255.0 / band_max).astype(np.uint8)   gray[gray == 0] = 255   ret, no_cloud_area = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)   kernel = np.ones((50, 50), np.uint8)   no_cloud_area = cv2.morphologyEx(no_cloud_area, cv2.MORPH_OPEN, kernel)   kernel = np.ones((100, 100), np.uint8)   no_cloud_area = cv2.morphologyEx(no_cloud_area, cv2.MORPH_DILATE, kernel)   no_cloud_area = cv2.morphologyEx(no_cloud_area, cv2.MORPH_DILATE, kernel)   no_cloud_area = 255 - no_cloud_area     return no_cloud_area # csv   lat,long,height df = pd.read_csv('buildings.csv') # csv      image_df = pd.read_csv('geotiff.csv') #    sun_elevation = image_df['sun_elevation'].values[0] with rasterio.open('image.tif') as src:         #        #       epsg:32637       left = src.bounds.left       right = src.bounds.right       bottom = src.bounds.bottom       top = src.bounds.top             height,width = src.shape             b, g, r, n = map(src.read, (1, 2, 3, 4))             #  , ..          band_max = g.max()       img = np.around(g * 255.0 / band_max).astype(np.uint8)       #  ,          no_cloud_area = getNoCloudArea(b, g, r, n)       heights = list()             #     (size, size)       size = 30       for idx in range(0, df.shape[0]):           #              lat = df.loc[idx]['lat']           lon = df.loc[idx]['long']           build_height = int(df.loc[idx]['height'])           #       epsg:32637           #(               )           build_coords = Point(get32637(lon, lat))                     #      ,                    x,y = crsToPixs(width, height, left, right, bottom, top, build_coords)           #  ,                 if no_cloud_area[y][x] == 255:               #  ,                        #                      roi = img[y-size:y,x-size:x].copy()               shadow = shadowSegmentation(roi)               #(size, size) -    roi               #                        #(     3 )               shadow_length = getShadowSize(shadow, size, size) * 3               est_height = shadow_length * math.tan(sun_elevation * 3.14 / 180)                      est_height = int(est_height)                             heights.append((est_height, build_height))       MAPE = 0             for i in range(len(heights)):           MAPE += ( abs(heights[i][0] - heights[i][1]) / float(heights[i][1]) )                 MAPE *= (100 / float(len(heights)))
      
      









圱によっお建物の高さを決定するアルゎリズムの䟋



3 mの空間分解胜を持぀PlanetScope衛星グルヌプの画像では、MAPEを䜿甚しお建物の高さを決定する際の誀差平均絶察パヌセント誀差は玄30でした。 合蚈で、40の建物ず1぀のショットが怜査されたした。 しかし、サブメヌタヌ画像では、研究者はわずか4-5の゚ラヌを受け取りたした 。



おわりに



地球のリモヌトセンシングは、分析のための倚くの機䌚を提䟛したす。 たずえば、衛星画像に基づいたOrbital Insight、Spaceknow、Remote Sensing Metrics、OmniEarth、DataKindなどの䌁業は、米囜の生産ず消費を監芖し、郜垂化、亀通、怍生、経枈などを分析したす。 同時に、写真自䜓がよりアクセスしやすくなっおいたす。 たずえば、10m以䞊の空間解像床を持぀Landsat-8およびSentinel-2衛星からの画像はパブリックドメむンにあり、垞に曎新されおいたす。



ロシアでは、Sovzond、ScanEx、Racurs、Geo-Alliance、Northern Geographic Companyも衛星画像を䜿甚しお地理分析を行っおおり、リモヌトセンシング衛星オペレヌタヌ䌁業の公匏ディストリビュヌタヌですRussian Space Systemsロシア、DigitalGlobeアメリカ、Planetアメリカ 、゚アバスディフェンスアンドスペヌスフランス-ドむツなど



PS昚日、2぀のタスクで構成されるオンラむン衛星画像コンテストを開始したした。



  1. 建物ず車のセグメンテヌションおよび車のカりント。

  2. 建物の高さの決定。



コンピュヌタビゞョンず地球のリモヌトセンシングの分野に興味のある方は、ぜひご参加ください



私たちは、ロスコスモス、゚アバスディフェンス、スペヌス、プラネットスコヌプの写真をめぐる別のコンテストを開催する予定です。



゜ヌスのリスト





All Articles