遙感圖像處理—幾何校正


  本節將從原理和代碼兩個方面講解遙感圖像的幾何校正。

原理

  首先介紹幾何校正的概念:在遙感成像過程中,傳感器生成的圖像像元相對於地面目標物的實際位置發生了擠壓、扭曲、拉伸和偏移等問題,這一現象叫做幾何畸變。幾何畸變會給遙感圖像的定量分析、變化檢測、圖像融合、地圖測量或更新等處理帶來的很大誤差,所以需要針對圖像的幾何畸變進行校正,即幾何校正。

  幾何校正分為幾何粗校正和幾何精校正。粗校正是利用空間位置變化關系,采用計算公式和輔助參數進行的校正,叫做系統幾何校正;精校正是在此基礎上,使圖像的幾何位置符合某種地理坐標系統,與地圖配准,調整亮度值,即利用地面控制點(GCP)做的幾何精校正。

  幾何校正步驟:1.空間位置的變換(像元坐標)2.像元灰度值的重新計算,即重采樣。

  1. 坐標變換

  坐標變換分為直接法和間接法。

  1)直接法:從原始圖像陣列出發,依次計算每個像元在輸出圖像中的坐標。直接法輸出的像元值大小不會發生變化,但輸出圖像中的像元分布不均勻。

  2)間接法:從輸出圖像陣列出發,依次計算每個像元在原始圖像中的位置,然后計算原始圖像在該位置的像元值,再將計算的像元值賦予輸出圖像像元。此方法保證校正后的圖像的像元在空間上均勻分布,但需要進行灰度重采樣。該方法是最常用的幾何校正方法。

 

  由上圖可見,直接法直接以原始圖像的坐標為基准點,坐標偏移到校正后的圖像,坐標的位置有很多出現在了像元的中間位置,所以直接輸出像元值大小導致像元分布不均勻。

  而對於間接法。以輸出圖像的坐標為基准點,已經定義在了格點的位置上,此時反算出該點在原始圖像上對應的圖像坐標,坐標多數落在像元的中間位置。這里采用最鄰近法、雙線性內插和三次卷積法來計算該點的灰度值,達成重采樣的目的。

 

  2. 重采樣

   圖像數據經過坐標變換之后,像元中心的位置發生改變,其在原始圖像的位置不一定是整數行\列,需要根據輸出圖像各像元在原始圖像中對應的位置,對原始圖像重采樣,建立新的柵格矩陣。

   主要有最近鄰法、雙線性內插法、三次卷積法。原理這里不再敘述。其中最近鄰法沒有改變圖像光譜信息,能保證定量分析的准確性,但是圖像不夠平滑。后兩者雖然數據連續平滑了,但是光譜信息遭到了破壞,比較適合於制圖,不適用於定量分析。

 

 

 代碼實現

     在熟悉了幾何校正的原理后,可以動手實現這一環節。這里主要介紹三種方法,具體如下。

    1.首先介紹最基礎也是最底層的方法。(這里是分步切片得到偏移后的坐標,然后重采樣)

from osgeo import gdal

def get_indices(source_ds, target_width, target_height):
    source_geotransform = source_ds.GetGeoTransform()
    source_width = source_ds.GetGeoTransform[1]
    source_height = source_ds.GetGeoTransform[5]
    dx = target_width/source_width
    dy = target_height/source_height
    target_x = np.arange(dx/2, source_ds.RasterXSize, dx)
    target_y = np.arange(dy/2, source_ds.RasterYSize, dy)
    return np.meshgrid(target_x, target_y)

def bilinear(in_data, x, y):
    x-=0.5
    y-=0.5
    x0=np.floor(x).astype(int)
    x1=x0+1
    y0=np.floor(y).astype(int)
    y1=y0+1
    
    ul=in_data[y0,x0]*(y1-y)*(x1-x)
    ur=in_data[y0,x1]*(y1-y)*(x-x0)
    ll=in_data[y1,x0]*(y-y0)*(x1-x)
    lr=in_data[y1,x1]*(y-y0)*(x-x0)

    return ul+ur+ll+lr

if __name__ =="__main__":
    in_fn=r''
    out_fn=r''
    cell_size=(0.02,-0.02)

    in_ds = gdal.Open(in_fn)
    x, y=get_indices(in_ds,*cell_size)
    outdata=bilinear(in_ds.ReadAsArray(), x, y)
    
    driver=gdal.GetDriverByName('GTiff')
    rows,cols=outdata.shape
    out_ds=driver.Create(out_fn,cols,rows,1,gdal.GDT_ Int32)

    gt=list(in_ds.GetGeoTransform())
    gt[1]=cell_size[0]
    gt[5]=cell_size[1]
    out_ds.SetGeoTransform(gt)
    
    out_band = out_ds.GetRasterBand(1)
    out_band.WriteArray(outdata)
    out_band.FlushCache()
    out_band.ComputeStatistics(False)

  2.第二種方法是ReadAsArray()函數,設置buf_xsize, buf_ysize這個緩沖區大小,就可以按這個大小重采樣(最鄰近法)。同時需要設置新的gt[1]\gt[5]以及行列數,這里代碼省略,有興趣查閱之前的gdal筆記。

  3.第三種方法是gdalwarp或gdal.ReprojectImage。這里有重采樣的部分,具體如下。

from osgeo import gdal, gdalconst

# 1.設置分辨率投影
# inputfile = r'E:\桌面文件保存路徑\GIS\test\quickbird_test.dat'
# outputfile = r'E:\桌面文件保存路徑\GIS\test\resampling_test.tif'
#
# inputds = gdal.Open(inputfile, gdal.GA_ReadOnly)  # 待重采樣圖像
# band1 = inputds.GetRasterBand(1)
# xsize = inputds.RasterXSize
# ysize = inputds.RasterYSize
# nbands = inputds.RasterCount
# inputProj = inputds.GetProjection()
# inputTrans = inputds.GetGeoTransform()
#
#
# new_x = int(xsize * (inputTrans[1] / 10))  # 計算新行列數
# new_y = int(ysize * (inputTrans[5] / -10)) # 注意抵消負號
#
# print(inputTrans[1])
# print(inputTrans[5])
#
# inputTrans = list(inputTrans)
# inputTrans[1] = 10  # 分辨率
# inputTrans[5] = -10 # 注意設置為-,否則無法SetGeoTransform
#
# print(inputTrans)
#
# driver = gdal.GetDriverByName('GTiff')
# out_ds = driver.Create(outputfile, new_x, new_y, nbands, band1.DataType)
# out_ds.SetGeoTransform(inputTrans)
# out_ds.SetProjection(inputProj)
#
# gdal.ReprojectImage(inputds, out_ds, inputProj, out_ds.GetProjection(), gdalconst.GRA_Bilinear)
#
# del out_ds

# 2.從圖1重采樣到圖2

inputfile = r'E:\桌面文件保存路徑\IDL\imgs\TMSPOT\TM-30m.img' #高光譜
referencefile = r'E:\桌面文件保存路徑\IDL\imgs\TMSPOT\bldr_sp.img' #高分辨率
outputfile = r'E:\test.tif'  #重采樣輸出圖像

inputras = gdal.Open(inputfile, gdal.GA_ReadOnly)  #待重采樣圖像,高光譜低分辨率
inputProj = inputras.GetProjection()
inputTrans = inputras.GetGeoTransform()
nbands = inputras.RasterCount

reference = gdal.Open(referencefile, gdal.GA_ReadOnly)  #目標圖像,高分辨率全色波段
referenceProj = reference.GetProjection()
referenceTrans = reference.GetGeoTransform()
bandreference = reference.GetRasterBand(1)
x = reference.RasterXSize
y = reference.RasterYSize


driver = gdal.GetDriverByName('GTiff')
output = driver.Create(outputfile, x, y, nbands, bandreference.DataType)
output.SetGeoTransform(referenceTrans)
output.SetProjection(referenceProj)

gdal.ReprojectImage(inputras, output, inputProj, referenceProj, gdalconst.GRA_Bilinear)

del output

  4.此外完整的幾何校正和重采樣還可以用opencv的一些api。

from matplotlib import pyplot as plt
import cv2
import numpy as np

img = cv2.imread('aier.jpg')
rows,cols = img.shape[:2]
pts1 = np.float32([[50,50],[200,50],[50,200]])  #對應校正點
pts2 = np.float32([[10,100],[200,20],[100,250]])
M = cv2.getAffineTransform(pts1,pts2)  //計算仿射變換矩陣
#第三個參數:變換后的圖像大小
res = cv2.warpAffine(img,M,(rows,cols)) //根據矩陣和圖像重采樣
plt.subplot(121)
plt.imshow(img[:,:,::-1])

plt.subplot(122)
plt.imshow(res[:,:,::-1])  #畫出圖片,但不顯示

plt.show() #顯示

  需要注明,本文中原理部分引用了朱文泉老師著書的內容,部分代碼摘自csdn博客。

    

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM