我试图检测从高空拍摄的图像中的地平线,以确定相机的方向。我也试图让它运行得更快 - 理想情况下,我希望能够在 Raspberry Pi 上实时处理帧(即每秒几帧)。到目前为止,我一直采用的方法是基于这样一个事实,即在高海拔地区天空非常黑暗,如下所示:
我所尝试的是从整个图像中取样并将它们分成明暗样本,并在它们之间画一条线。然而,由于大气的模糊性,这会将地平线置于其实际位置之上:
这是我的代码(使用 Javascript 以方便网络演示):
function mag(arr) {
return Math.sqrt(arr[0]*arr[0]+arr[1]*arr[1]+arr[2]*arr[2])
}
// return (a, b) that minimize
// sum_i r_i * (a*x_i+b - y_i)^2
function linear_regression( xy ) {
var i,
x, y,
sumx=0, sumy=0, sumx2=0, sumy2=0, sumxy=0, sumr=0,
a, b;
for(i=0;i<xy.length;i++) {
x = xy[i][0]; y = xy[i][2];
r = 1
sumr += r;
sumx += r*x;
sumx2 += r*(x*x);
sumy += r*y;
sumy2 += r*(y*y);
sumxy += r*(x*y);
}
b = (sumy*sumx2 - sumx*sumxy)/(sumr*sumx2-sumx*sumx);
a = (sumr*sumxy - sumx*sumy)/(sumr*sumx2-sumx*sumx);
return [a, b];
}
var vals = []
for (var i=0; i<resolution; i++) {
vals.push([])
for (var j=0; j<resolution; j++) {
x = (canvas.width/(resolution+1))*(i+0.5)
y = (canvas.height/(resolution+1))*(j+0.5)
var pixelData = cr.getImageData(x, y, 1, 1).data;
vals[vals.length-1].push([x,y,pixelData])
cr.fillStyle="rgb("+pixelData[0]+","+pixelData[1]+","+pixelData[2]+")"
cr.strokeStyle="rgb(255,255,255)"
cr.beginPath()
cr.arc(x,y,10,0,2*Math.PI)
cr.fill()
cr.stroke()
}
}
var line1 = []
var line2 = []
for (var i in vals) {
i = parseInt(i)
for (var j in vals[i]) {
j = parseInt(j)
if (mag(vals[i][j][3])<minmag) {
if ((i<(vals.length-2) ? mag(vals[i+1][j][4])>minmag : false)
|| (i>0 ? mag(vals[i-1][j][5])>minmag : false)
|| (j<(vals[i].length-2) ? mag(vals[i][j+1][6])>minmag : false)
|| (j>0 ? mag(vals[i][j-1][7])>minmag : false)) {
cr.strokeStyle="rgb(255,0,0)"
cr.beginPath()
cr.arc(vals[i][j][0],vals[i][j][8],10,0,2*Math.PI)
cr.stroke()
line1.push(vals[i][j])
}
}
else if (mag(vals[i][j][9])>minmag) {
if ((i<(vals.length-2) ? mag(vals[i+1][j][10])<minmag : false)
|| (i>0 ? mag(vals[i-1][j][11])<minmag : false)
|| (j<(vals[i].length-2) ? mag(vals[i][j+1][12])<minmag : false)
|| (j>0 ? mag(vals[i][j-1][13])<minmag : false)) {
cr.strokeStyle="rgb(0,0,255)"
cr.beginPath()
cr.arc(vals[i][j][0],vals[i][j][14],10,0,2*Math.PI)
cr.stroke()
line2.push(vals[i][j])
}
}
}
}
eq1 = linear_regression(line1)
cr.strokeStyle = "rgb(255,0,0)"
cr.beginPath()
cr.moveTo(0,eq1[1])
cr.lineTo(canvas.width,canvas.width*eq1[0]+eq1[1])
cr.stroke()
eq2 = linear_regression(line2)
cr.strokeStyle = "rgb(0,0,255)"
cr.beginPath()
cr.moveTo(0,eq2[1])
cr.lineTo(canvas.width,canvas.width*eq2[0]+eq2[1])
cr.stroke()
eq3 = [(eq1[0]+eq2[0])/2,(eq1[1]+eq2[1])/2]
cr.strokeStyle = "rgb(0,255,0)"
cr.beginPath()
cr.moveTo(0,eq3[1])
cr.lineTo(canvas.width,canvas.width*eq3[0]+eq3[1])
cr.stroke()
结果(绿线是检测到的地平线,红色和蓝色是估计在边界外):
我该如何改进?有没有更有效的方法来做到这一点?最终的程序可能会用 Python 或 C 编写,如果太慢的话。