पायथन में एक रेखापुंज पर बिंदु डेटा का बिलिनियर प्रक्षेप?


12

मेरे पास एक रेखापुंज है जिसके साथ मैं कुछ बिंदु प्रक्षेप करना चाहूंगा। यहाँ मैं कहाँ हूँ:

from osgeo import gdal
from numpy import array

# Read raster
source = gdal.Open('my_raster.tif')
nx, ny = source.RasterXSize, source.RasterYSize
gt = source.GetGeoTransform()
band_array = source.GetRasterBand(1).ReadAsArray()
# Close raster
source = None

# Compute mid-point grid spacings
ax = array([gt[0] + ix*gt[1] + gt[1]/2.0 for ix in range(nx)])
ay = array([gt[3] + iy*gt[5] + gt[5]/2.0 for iy in range(ny)])

अब तक, मैंने SciPy के interp2d फ़ंक्शन को आज़माया है:

from scipy import interpolate
bilinterp = interpolate.interp2d(ax, ay, band_array, kind='linear')

हालाँकि मुझे 317 × 301 रेखापुंज के साथ अपने 32-बिट विंडोज सिस्टम पर एक मेमोरी त्रुटि मिलती है:

Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "C:\Python25\Lib\site-packages\scipy\interpolate\interpolate.py", line 125, in __init__
    self.tck = fitpack.bisplrep(self.x, self.y, self.z, kx=kx, ky=ky, s=0.)
  File "C:\Python25\Lib\site-packages\scipy\interpolate\fitpack.py", line 873, in bisplrep
tx,ty,nxest,nyest,wrk,lwrk1,lwrk2)
MemoryError

मैं मानता हूँ, मुझे इस SciPy फ़ंक्शन में सीमित विश्वास है, क्योंकि bounds_errorया fill_valueपैरामीटर दस्तावेज के रूप में काम नहीं करते हैं। मैं यह नहीं देखता कि मुझे मेमोरी त्रुटि क्यों होनी चाहिए, क्योंकि मेरा रेखापुंज 317 × 301 है, और बिलिनियर एल्गोरिथ्म मुश्किल नहीं होना चाहिए।

किसी को एक अच्छा बिलिनियर प्रक्षेप एल्गोरिथ्म भर में आया है, अधिमानतः अजगर में, संभवतः NumPy के साथ सिलवाया गया है? कोई संकेत या सलाह?


(नोट: निकटतम पड़ोसी प्रक्षेप एल्गोरिथ्म आसान केक है:

from numpy import argmin, NAN

def nearest_neighbor(px, py, no_data=NAN):
    '''Nearest Neighbor point at (px, py) on band_array
    example: nearest_neighbor(2790501.920, 6338905.159)'''
    ix = int(round((px - (gt[0] + gt[1]/2.0))/gt[1]))
    iy = int(round((py - (gt[3] + gt[5]/2.0))/gt[5]))
    if (ix < 0) or (iy < 0) or (ix > nx - 1) or (iy > ny - 1):
        return no_data
    else:
        return band_array[iy, ix]

... लेकिन मैं बिलिनियर इंटरपोलेशन विधियों को बहुत पसंद करता हूं)


1
हो सकता है कि आप प्राप्त करें MemoryErrorक्योंकि NumPy आपके परे पहुंचने की कोशिश करता है band_array? आप की जाँच करनी चाहिए axऔर ay
ओल्ट

1
कुल्हाड़ी, ay एक समस्या हो सकती है अगर ग्रिड बिल्कुल घुमाया जाए। बेहतर हो सकता है कि अपने इंटरपोल को बिंदुओं को पिक्सेल या डेटा निर्देशांक में बदल दें। इसके अलावा, अगर उनके साथ कोई समस्या है, तो आप बैंड के आकार से परे जा सकते हैं।
डेव एक्स

सही, घुमाए गए ग्रिड को ग्रिड-स्पेस में परिवर्तन की आवश्यकता होती है, फिर समन्वय-अंतरिक्ष में वापस। इसके लिए एफाइन ट्रांसफॉर्म गुणांक के विलोम की आवश्यकता होती है gt
माइक टी

जवाबों:


7

मैंने पायथन में नीचे दिए गए सूत्र ( विकिपीडिया से ) का अनुवाद किया है ।

from numpy import floor, NAN

def bilinear(px, py, no_data=NAN):
    '''Bilinear interpolated point at (px, py) on band_array
    example: bilinear(2790501.920, 6338905.159)'''
    ny, nx = band_array.shape
    # Half raster cell widths
    hx = gt[1]/2.0
    hy = gt[5]/2.0
    # Calculate raster lower bound indices from point
    fx = (px - (gt[0] + hx))/gt[1]
    fy = (py - (gt[3] + hy))/gt[5]
    ix1 = int(floor(fx))
    iy1 = int(floor(fy))
    # Special case where point is on upper bounds
    if fx == float(nx - 1):
        ix1 -= 1
    if fy == float(ny - 1):
        iy1 -= 1
    # Upper bound indices on raster
    ix2 = ix1 + 1
    iy2 = iy1 + 1
    # Test array bounds to ensure point is within raster midpoints
    if (ix1 < 0) or (iy1 < 0) or (ix2 > nx - 1) or (iy2 > ny - 1):
        return no_data
    # Calculate differences from point to bounding raster midpoints
    dx1 = px - (gt[0] + ix1*gt[1] + hx)
    dy1 = py - (gt[3] + iy1*gt[5] + hy)
    dx2 = (gt[0] + ix2*gt[1] + hx) - px
    dy2 = (gt[3] + iy2*gt[5] + hy) - py
    # Use the differences to weigh the four raster values
    div = gt[1]*gt[5]
    return (band_array[iy1,ix1]*dx2*dy2/div +
            band_array[iy1,ix2]*dx1*dy2/div +
            band_array[iy2,ix1]*dx2*dy1/div +
            band_array[iy2,ix2]*dx1*dy1/div)

ध्यान दें कि परिणाम स्रोत डेटा की तुलना में एक स्पष्ट उच्च परिशुद्धता के साथ वापस आ जाएगा, क्योंकि यह NumPy के dtype('float64')डेटा प्रकार पर निर्भर है । .astype(band_array.dtype)आउटपुट डेटा प्रकार इनपुट सरणी के समान बनाने के लिए आप रिटर्न मान का उपयोग कर सकते हैं ।

बिलिनियर इंटरपोलेशन फॉर्मूला


3

मैंने इसे समान परिणामों के लिए स्थानीय रूप से आज़माया, लेकिन मैं 64-बिट प्लेटफ़ॉर्म पर हूं इसलिए यह मेमोरी सीमा से नहीं टकराया। शायद इसके बजाय एक बार में सरणी के छोटे टुकड़ों को प्रक्षेपित करने की कोशिश करें, जैसे कि इस उदाहरण में

आप इसे GDAL के साथ भी कर सकते हैं, कमांड लाइन से यह होगा:

gdalwarp -ts $XSIZE*2 0 -r bilinear input.tif interp.tif

पायथन में समतुल्य ऑपरेशन करने के लिए, ReprojectImage () का उपयोग करें :

mem_drv = gdal.GetDriverByName('MEM')
dest = mem_drv.Create('', nx, ny, 1)

resample_by = 2
dt = (gt[0], gt[1] * resample_by, gt[2], gt[3], gt[4], gt[5] * resample_by)
dest.setGeoTransform(dt)

resampling_method = gdal.GRA_Bilinear    
res = gdal.ReprojectImage(source, dest, None, None, resampling_method)

# then, write the result to a file of your choice...    

मेरे बिंदु डेटा जो मैं प्रक्षेप करना चाहूंगा, वे नियमित रूप से नहीं होते हैं, इसलिए मैं GDAL की अंतर्निहित ReprojectImageतकनीक का उपयोग नहीं कर सकता ।
माइक टी

1

मेरे पास अतीत में सटीक मुद्दा रहा है, और कभी भी इसे interpolate.interp2d का उपयोग करके हल नहीं किया गया है। मुझे scipy.ndimage.map_coordinates का उपयोग करके सफलता मिली है । निम्नलिखित का प्रयास करें:

scipy.ndimage.map_coordinates (band_array, [ax, ay]], ऑर्डर = 1)

यह बिलिनियर के समान आउटपुट देता है।


मैं इस एक के द्वारा थोड़ा सा फेंक दिया गया था, क्योंकि मैं अनिश्चित हूं कि स्रोत रेखापुंज निर्देशांक का उपयोग कैसे किया जाता है (पिक्सेल निर्देशांक का उपयोग करने के बजाय)। मैं देखता हूं कि कई बिंदुओं को हल करने के लिए यह "सदिश" है।
माइक टी

सहमत, मैं वास्तव में डरपोक नहीं समझता। आपका सुन्न समाधान बेहतर है।
मैथ्यू स्नेप

0

scipy.interpolate.interp2d () अधिक आधुनिक स्काइप के साथ ठीक काम करता है। मुझे लगता है कि पुराने संस्करण अनियमित ग्रिड मानते हैं और नियमित ग्रिड का लाभ नहीं उठाते हैं। मुझे वैसी ही त्रुटि मिलती है जैसी आप चुस्ती से करते हैं। संस्करण = 0.11.0, लेकिन डरपोक पर। संस्करण = 0.14.0, यह खुशी से कुछ 1600x1600 मॉडल आउटपुट पर काम करता है।

आपके प्रश्न में संकेत के लिए धन्यवाद।

#!/usr/bin/env python

from osgeo import gdal
from numpy import array
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("filename",help='raster file from which to interpolate a (1/3,1/3) point from from')
args = parser.parse_args()

# Read raster
source = gdal.Open(args.filename)
nx, ny = source.RasterXSize, source.RasterYSize
gt = source.GetGeoTransform()
band_array = source.GetRasterBand(1).ReadAsArray()
# Close raster
source = None

# Compute mid-point grid spacings
ax = array([gt[0] + ix*gt[1] + gt[1]/2.0 for ix in range(nx)])
ay = array([gt[3] + iy*gt[5] + gt[5]/2.0 for iy in range(ny)])

from scipy import interpolate
bilinterp = interpolate.interp2d(ax, ay, band_array, kind='linear')

x1 = gt[0] + gt[1]*nx/3
y1 = gt[3] + gt[5]*ny/3.

print(nx, ny, x1,y1,bilinterp(x1,y1))

####################################

$ time ./interp2dTesting.py test.tif 
(1600, 1600, -76.322, 30.70889, array([-8609.27777778]))

real    0m4.086s
user    0m0.590s
sys 0m0.252s
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.