【问题标题】:What is the best way to check all pixels within certain radius?检查特定半径内所有像素的最佳方法是什么?
【发布时间】:2015-10-16 04:45:27
【问题描述】:

我目前正在开发一个应用程序,它会在下雨时提醒用户。为此,我想检查用户位置周围的某些区域是否有降雨(降雨雷达图像上不同像素颜色的强度)。我希望选中的区域是一个圆圈,但我不知道如何有效地做到这一点。

假设我想检查 50 公里的半径。我目前的想法是获取大小为 100kmx100km 的图像子集(用户 + 50 公里西,用户 + 50 公里东,用户 + 50 公里北,用户 + 50 公里南),然后检查该子集中的每个像素,如果它比 50 公里更接近用户。

我的问题是,有没有更好的解决方案来解决这类问题?

【问题讨论】:

    标签: algorithm area euclidean-distance


    【解决方案1】:

    如果您正在搜索的事件(下雨或其他任何事物)的发生相对较少,那么扫描一个 正方形 或像素并没有错,然后,只有在检测到该正方形中的雨后,检查下雨是否在所需的 50 公里范围内。请注意,这里的关键点是您不需要检查正方形的 每个 像素是否在圆圈内(这将非常低效),您必须搜索您的事件(下雨)首先,只有当你找到它时,检查它是否落入50公里圈内。为了有效地实现这一点,您还必须制定一些巧妙的策略来处理图像上的多像素雨水“污点”。

    但是,由于您正在扫描光栅图像,因此您可以轻松实现众所周知的Bresenham circle algorithm 来查找每条扫描线的圆的起点和终点。这样您就可以轻松地将扫描范围限制在所需的 50 公里半径内。

    再想一想,您甚至不需要 Bresenham 算法。对于正方形中的每一行像素,计算该行与 50 公里圆的交点(使用带有平方根的常用教科书公式),然后检查落在这些交点之间的所有像素。以相同的方式处理所有行,您就完成了。

    附:不幸的是,我链接的维基百科页面根本没有提供 Bresenham 算法。它有米切纳圆算法的代码。 Michener 算法也适用于圆形光栅化目的,但它不如 Bresenham 算法精确。如果您关心精度,请在某个地方找到真正的 Bresenham。实际上在网上很难找到:大多数搜索结果都错误地将米切纳呈现为布雷森汉姆。

    【讨论】:

      【解决方案2】:

      也许您可以尝试一些可以加快算法速度的方法。

      在蛮力算法中你可能会使用方程:

      (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 个,迭代并找到半径为 50 公里边界的所有对 (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】:
        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
        

        【讨论】:

          【解决方案4】:

          有,您可以修改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;
          }
          

          【讨论】:

            猜你喜欢
            • 2020-09-07
            • 2021-02-18
            • 2018-07-24
            • 2018-03-19
            • 1970-01-01
            • 1970-01-01
            • 2016-07-02
            • 1970-01-01
            • 2016-11-27
            相关资源
            最近更新 更多