正射影像
攝影測量 的第二個作業,不只幾何改正, 把傾斜攝影的照片作成正射影像。 我就用上學期的 code, 加上上次作業寫的影像取樣, 組合成影像正射化的程式。
上學期的 bottom up 共線式
上學期 航遙測概論 最後產出是一個 bottom up 共線式, 輸入內外方位參數,能把物空間座標轉到相空間; 或把相空間座標和高程,轉成物空間; 並作透鏡畸變改正。
上學期是用 coffee script 寫的, 寫太爛現在根本不忍直視,就不改了,直接引用。 反正結果是對的就好。
範例
// 引用
const ColinearityEquation = require('colinearityEquation')
// 下面是使用方法
// 外方位參數
const eop = {
// 平移減少計算誤差
// xo: 169570.443932,
xo: 570.443932,
// yo: 2544089.886767,
yo: 89.886767,
zo: 116.355578,
// 角度轉弧度
omega: 25.769170/180*Math.PI,
phi: -0.478151/180*Math.PI,
kappa:-4.904690/180*Math.PI
}
// 內方位參數
const xp = 0.00797976759482130898
const yp = -0.01632040141493363086
const c = 3.68128070687046982101
const iop = [xp, yp, -c]
// 透鏡畸變
iop.k = [
-0.00261341937662040030,
0.00015213497306022675,
-0.00000127943044334018
]
iop.p = [0.00002392585197592054, 0.00001764654855396589]
// 輸入內外方位參數,創建共線式物件
const ce = new ColinearityEquation(eop, iop)
// tw97 (2544200, 169100, 19)
ce.groundToPhoto([200, 100, 19]) // 輸出像座標 [0.3, 0.1, 0]
// 像空間到物空間未知數不足,
// 要物空間 X Y Z 任一已知,這裡是高程 Z 已知為正高 19m。
ce.photoToGround([0.3, 0.1, 0], [NaN, NaN, 19]) // 輸出物座標 [200, 100, 19]
上次作業的影像處理程式
上次作業寫的程式: 輸入物空間到像空間的轉換函數, 和物空間轉換範圍、取樣距離; 就能把從該範圍自動取樣, 把每個地物座標用輸入的函數轉到像座標, 取該像座標的顏色填到物空間。
但上學期轉出來的結果是像空間座標, 要轉成 pixel 要乘上 pixel size 再平移, 所以要多一層轉換函數。
// 引用
const ReferenceImage = require('reference-image').ReferenceImage
const X = 0
const Y = 1
const Z = 2
// 輸入檔名和物空間到像空間的轉換函數,
// 構造一個 reference image 物件。
const imgp = new ReferenceImage('DJI_0339.jpg', groundToPhoto)
function groundToPhoto(ground) {
// 補上高程座標
ground[Z] = 19.7
// 甪上面的共線式轉換物空間到像空間
const photo = ce.groundToPhoto(ground)
// 從像空間轉到 pixel 值
const scale = 631.8955603017934
const pixel = point.map((length) => length * scale)
scalePoint[X] = 1995.5 - scalePoint[X]
scalePoint[Y] = 1495.5 + scalePoint[Y]
return scalePoint
}
imgp.then((img) => {
// 轉換範圍,座標是平移 (-2544000, -169000, 0) 的 twd97
const start = [100, 300]
const end = [200, 500]
img.gsd = 0.1 // 0.1m = 10cm 約要跑半小時
return img.reference(start, end)
}).then((referenceImage) => {
// 轉換完存檔
referenceImage.write('DJI_0339-ortho.png')
})
方向相反
發現之前寫的程式有部份寫錯, 造成轉出來的結果上下相反。所以就改了。 上一次的作業沒有要比較實際座標, 這次才有,才發現數字不太對; 不然都只關注有沒有扭曲而已。
主要是像空間是原點在光軸中心, 而數位影像是用 pixel,原點在左上角, Y 座標方向是相反的。
包裝
之後因為有三張影像,就把共同的部份抽出來,寫成一個函數。 輸入檔名、內外方位、範圍、取樣區間,就能轉換好。 github 原始碼 。
const ortho = require('./ortho')
ortho.run(file, eop, iop, [start, end], gsd)
轉換一張 250x200,gsd 設 0.1m, 也就是 2500x2000=5000000 個點, 約耗時 30 分鐘;一秒轉換 2777 個點。
成果
轉換成果是扇型,因為是傾斜攝影。 有些樹或建築被壓到地上, 因為沒有 dtm,轉換時一律把高程設成 19.6, 差不多是球場的高度。
超出相片範圍我沒有處理, Jimp 的作法還是一樣內插,就用最近的點, 就變成從邊界延伸一條一條的了。
js [flk.fig(339, 'DJI_0339-ortho'),
flk.fig(340, 'DJI_0340-ortho'),
flk.fig(341, 'DJI_0341-ortho')]
可以看出各張影像有些微不同, 像是從不同角度傾斜拍攝。 可能是因為沒有用 dtm,高程用同一數值的結果。
分析
之後放到 QGIS 裡,點出各控制點在不同照片的座標, 再和真實座標比較:
js flk.gn('vector-clean-map')
圖中向量是從控制點真實座標, 延伸往正射後影像中量測的控制點位置, 為了明顯看出系統誤,再延伸五倍的結果。 而底圖是正射後的 340 影像。
三張正射影像,誤差方向不同, 也分別在北中南為誤差最小處。 東邊的球場,因為正高差較多,所以都偏較多。
系統來說, 預估誤差方向的作法是將共線式的向量投影到地面上, 高程值如果有誤,就會延向量投影方向移動。 移動方向和拍攝傾角有關,因傾角會影響共線式的向量。
js flk.gn('error-dtm')