【问题标题】:How to group near coordinates如何对附近的坐标进行分组
【发布时间】:2014-01-22 20:29:19
【问题描述】:

我的论文是“多项选择考试检查器”,我对如何处理我的问题有一个大问题。我在这里得到了一张图片(特别是位图),所以你可以看到:

这是带有检测框的图像,我将对此进行描述:

  • 这是一份试卷,1-50 道题。每个数字都有一个对应的方框(数字右侧,作为答案的容器)
  • 此图片只是一个示例,检测到的框数可能会有所不同。我的估计是它包含 150-200 个检测到的框。
  • 每个检测框都存储在一个 List(MCvBOX2D) 中,其中包含 检测框的大小、中心等
  • 我将这些中心坐标转移到一个新列表中 List(PointF) center;
  • 图像中的每个框可能有 3-5 个检测框。如您所见,图像中的每个框中都有多个检测框。
  • 我按升序对所有检测到的框进行了排序,所以我会知道哪个可能是 number1、number2 等等..

这是我的一些代码,其中包含盒子的排序。

List<PointF> center = new List<PointF>();
List<PointF> centernew = new List<PointF>();
foreach (MCvBox2D box in lstRectangles)
{
   // this code transfers every center-coordinates of detected boxes 
   // to a new list which is center
    center.Add(new PointF(box.center.X, box.center.Y));
}
// and this one sorts the coordinates in ascending order.
centernew = center.OrderBy(p => p.Y).ThenBy(p => p.X).ToList(); 
  • 我已经完成了排序部分,现在我的问题是,由于图像中的每个盒子中检测到很多盒子,我想group sortedlist 中心坐标,所以我可以消除其他检测框,每个数字只得到一个检测框。

  • 我知道这很难理解,所以我会解释更多。

    假设我的 检测框排序列表 包含前五个中心坐标,它们是:

假设这是图像第一个框的每个检测框的中心坐标。

 center[0] = [ 45.39, 47.6]
 center[1] = [ 65.39, 47.6]
 center[2] = [ 45.40, 47.10]
 center[3] = [ 65.45, 47.25]
 center[4] = [ 46.01, 47.50]

and the 2nd are:

 center[5] = [ 200.39, 47.2]
 center[6] = [ 45.39, 47.2]
 center[7] = [ 45.39, 47.3]
 center[8] = [ 45.39, 47.55]
  • 我的目标是在列表中组织所有已排序的检测框,我必须能够将所有与另一个中心值接近的中心坐标分组,特别是它们的 Y 坐标。

【问题讨论】:

  • 包含 9 个项目的示例列表的输出应该是什么?
  • 我的输出应该只有 50 个检测到的框,即 50 个中心坐标。第 1 组和第 2 组坐标是相似但不精确的坐标,它们是检测到某个框的框的中心坐标。

标签: c# list coordinates points


【解决方案1】:
var rand = new Random();
var threshold = 1;
var points = new List<PointF>();

for (int i = 0; i < 20; i++)
{
    points.Add(new PointF((float) rand.NextDouble()*10, (float) rand.NextDouble()*10));
}

Console.WriteLine(points.Count);

for (int i = 0; i < points.Count(); i++)
{
    for (int j = i + 1; j < points.Count(); )
    {
        var pointHere = points[i];
        var pointThere = points[j];

        var vectorX = pointThere.X - pointHere.X;
        var vectorY = pointThere.Y - pointHere.Y;

        var length = Math.Sqrt(Math.Pow(vectorX, 2) + Math.Pow(vectorY, 2));

        if (length <= threshold)
        {
            points.RemoveAt(j);
        }
        else
        {
            j += 1;
        }
    }
}

Console.WriteLine(points.Count);

【讨论】:

  • 你好,我得到了正确的输出。非常好的答案,如果我没记错的话,这是两点之间的距离?我只是想知道那个 Random() 代码是干什么用的?
  • 只是一个完整工作示例的一些示例数据。你所追求的是中心之间的矢量长度......虽然它的蛮力。如果您想要“更好”的解决方案,请查看最近邻搜索。也就是说,这将减少您必须检查的点数,并使您的代码运行得更快。 alglib.net/other/nearestneighbors.php
【解决方案2】:

您可以计算给定点与列表中任何其他点之间的距离。如果距离小于一个盒子宽度的一半,你可以很确定它是同一个盒子的一部分。

double threshold = 3.0;  // Make this whatever is appropriate

for (int i = center.Count - 1; i >= 0; --i)
    if (center.Any(p => p != center[i] && Distance(center[i], p) < threshold))
        center.Remove(center[i]);

您可以将其用于您的 Distance() 方法:

private double Distance(PointF p1, PointF p2)
{
    double deltaX = Math.Abs(p1.X - p2.X);
    double deltaY = Math.Abs(p1.Y - p2.Y);

    return Math.Sqrt((deltaX * deltaX) + (deltaY * deltaY));
}

【讨论】:

    【解决方案3】:

    您可以将 Distinct 与自定义 IEqualityComparer (see MSDN) 一起使用。

    例如,定义一个类:

    class BoxEqualityComparer : IEqualityComparer<MCvBox2D>
    {
        private static Double Tolerance = 0.01; //set your tolerance here
    
        public Boolean Equals(MCvBox2D b1, MCvBox2D b2)
        {
            if (CentersAreCloseEnough(b1.Center, b2.Center))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    
        private Boolean CentersAreCloseEnough(PointF c1, PointF c2)
        {
            return Math.Abs(c1.X - c2.X) < Tolerance && Math.Abs(c1.Y - c2.Y) < Tolerance;
        }
    
    }
    

    然后像这样在代码中使用该方法:

    var distinctRectangles = lstRectangles.Distinct(new BoxEqualityComparer());
    

    您可以随意实现CentersAreCloseEnough(PointF c1, PointF c2);您可以使用矢量距离、x 和 y 中的绝对距离等。

    【讨论】:

      【解决方案4】:

      如果您只关心 Y 坐标的位置,只需按该数字排序。如果要对两者进行排序,可以同时添加 X 和 Y 并使用该数字对它们进行排序。这是我的意思的一个例子。

          for(int i = 0; i < points.length - 1; i++)
          {
              int temp = points[i].x + points[i].y;
      
              for(int j = i+1; j < points.length; i++)
              {
                   int temp2 = point[j].x + points[j].y;
      
                   if(temp2 < temp)
                   {
                       Point jugglePoint = points[i];
                       points[i] = points[j];
                       points[j] = jugglePoint;
                   }
              }
          }
      

      【讨论】:

      • @Katianie-嗨,我已经按升序对我的点进行了排序,我的问题是有多余的点,并不是真的多余,因为它们不完全相同。但是,它们非常相似。也许有一点不同。我想消除那些非常相似的点,只保留一个中心坐标。
      • 您可以尝试取每个点之间的差异,看看它是否 > 一定数量以及是否保留它。它可能是一个类似的双重循环
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      • 2012-06-15
      • 2019-01-03
      • 1970-01-01
      • 2014-04-03
      • 1970-01-01
      相关资源
      最近更新 更多