我目前正在开发一个应用程序来提醒用户下雨。为此,我想检查用户位置周围的某些区域是否有降雨(降雨雷达图像上强度的不同像素颜色)。我希望选中的区域是一个圆圈,但我不知道如何有效地做到这一点。
假设我想检查半径50km。我目前的想法是拍摄尺寸为100kmx100km(用户+西50km,用户+北50km,用户+南50km)的图像子集,然后检查该子集中的每个像素是否接近用户而不是50km。
我的问题是,有没有更好的解决方案用于此类问题?
答案 0 :(得分:3)
如果您正在搜索的事件(下雨或其他任何事件)发生的情况相对较少,那么扫描 square 或像素并没有问题,然后,只有在检测到雨后在那个方格中,检查下雨是否在所需的50公里圈内。请注意,此处的关键点是,您不需要检查广场的每个像素是否在圈内(效率非常低),您必须搜索您的事件(雨)首先,只有当你找到它时,检查它是否落入50公里的圆圈。为了有效地实现这一点,您还必须开发一些智能策略来处理多像素"污渍"你的形象下雨。
但是,由于您正在扫描光栅图像,因此可以轻松实现众所周知的Bresenham circle algorithm以查找每条扫描线的圆的起点和终点。这样,您可以轻松地将扫描限制在所需的50公里半径范围内。
在第二个想法中,你甚至不需要Bresenham算法。对于方形中的每一行像素,计算该行与50km圆的交点(使用通常的平方根教科书公式),然后检查落在这些交点之间的所有像素。以相同的方式处理所有行,您就完成了。
P.S。不幸的是,我链接的维基百科页面根本没有提供Bresenham算法。它具有代码为Michener circle算法。米歇尔算法也适用于圆光栅化目的,但它不如Bresenham算法精确。如果您关心精确度,请在某处找到真正的Bresenham。实际上,在网上找到令人惊讶的难度:大多数搜索命中错误地将米歇尔视为布雷森汉姆。
答案 1 :(得分:1)
有,你可以修改midpoint circle algorithm给你一个每个y的数组,圆圈开始的x坐标(并且结束,由于对称性,它是相同的东西)。这个数组很容易计算,下面是伪代码。
然后你可以完全迭代正确的部分,而无需检查任何东西。
伪代码:
data = new int[radius];
int f = 1 - radius, ddF_x = 1;
int ddF_y = -2 * radius;
int x = 0, y = radius;
while (x < y)
{
if (f >= 0)
{
y--;
ddF_y += 2; f += ddF_y;
}
x++;
ddF_x += 2; f += ddF_x;
data[radius - y] = x; data[radius - x] = y;
}
答案 2 :(得分:0)
也许您可以尝试一些可以加速算法的方法。
在强力算法中,您可能会使用等式:
(x-p)^2 + (y-q)^2 < r^2
(p,q) - center of the circle, user position
r - radius (50km)
如果你想找到满足上述条件的所有像素(x,y)并检查它们,你的算法会转到O(n ^ 2)
我只会检查圆圈边框上的像素,而不是扫描此圆圈中的所有像素。
在这种情况下,您可以使用更聪明的方式来定义圆圈。
x = p+r*cos(a)
y = q*r*sin(a)
a - angle measured in radians [0-2pi]
现在你可以采样一些角度,例如其中的20个,迭代并找到半径为50km的所有边界(x,y)。现在检查它们是否在雨区并提醒用户。
为了更安全,我建议你使用多个弧度(小于50公里),因为你的整个雨云可能在圆圈内,你的应用程序将无法识别他。例如,使用3个环(r = 5km,15km,30km)并做同样的事情。该算法的效率仅取决于角度数和圈数。
伪代码将是:
checkRainDanger()
p,q <- position
radius[] <- array of radii
for c = 1 to length(radius)
a=0
while(a<2*pi)
x = p + radius[c]*cos(a)
y = q + radius[c]*sin(a)
if rainZone(x,y)
return true
else
a+=pi/10
end_while
end_for
return false //no danger
答案 3 :(得分:-1)
r2=r*r
for x in range(-r, +r):
max_y=sqrt(r2-x*x)
for y in range(-max_y, +max_y):
# x,y is in range - check for rain