如何从未排序的x / y坐标数组中找到直线

时间:2016-01-17 08:40:44

标签: java algorithm line

是否有一种有效的算法可以从未排序的x / y坐标集合中找到直线? 如果符合以下条件,那将是理想的:

  • 只有在至少n(多于两个)点对齐时才会识别一条线。
  • 它允许公差,因此例如以下三个坐标将被视为(水平)线:10 / 100,20 / 99,30 / 100.

是否有某种标准方法可以解决这个问题?也许任何(java)库?你会如何解决它?

5 个答案:

答案 0 :(得分:0)

我建议使用两张地图,一张用于水平线,另一张用于垂直线。

对于每个点,键是X或Y坐标,值是点(使用点列表作为值)。现在浏览一下地图,如果有多个点,每个键显示点数,对于每个键,你还应该计算下一个键中的点数(如99和100的情况)。

答案 1 :(得分:0)

除非你已经知道这些点之间的某些关系,否则我不确定它是否是一种有效的算法。 我想在下面概述的算法将在n ^ 4时间运行。

你有

之类的东西
public class Line
{
    static float tolerance;
    float m, cLower, cUpper;
    ArrayList<Point> onThisLine = new ArrayList<Point>();

    public Line(double m, double c)
    {
        this.m = m;
        cLower = c-tolerance;
        cUpper = c+tolerance;
    }

    public boolean fitsInLine(Point xy)
    {...}

    public void addToList(Point xy)
    {...}
}

其中m和c代表我们在高中学到的直线的梯度和常数。

对于每个点,您必须将其与其他每个点进行比较,生成一个Line对象,然后将新的Line对象与每个现有的Line进行比较,如果它还不存在,则添加它。请注意,由于您允许的轻微容差,因此必须允许线之间的相似性。 例如,y = -x / 10 + 101和y = 100是非常相似的线方程。

最后,对于每个Line对象,您可以获得ArrayList的大小,保持适合它的Point,并丢弃Point比您想要的更少的行。

答案 2 :(得分:0)

如果你取一对点P i 和P j ,你可以在O(n)时间检查哪些点位于P i P j 。有O(n 2 )对,因此您得到的算法是O(n 3 )。当然,如果P k 正好在P i P j 的行上,则不应再检查P i P k 和P j P k ,因为它们将包含与P i P <相同的点子>Ĵ。但是,如果P k 接近P i P j ,则情况并非如此。

答案 3 :(得分:0)

我已经将算法显示在下面。它的作用是计算线的公式:y = kx + l;然后它产生两条平行于那条线的线,一条略微抬起,一条稍微降低 - >(y = kx + 1-d,y = kx + 1 + d,d =公差)。然后它通过其余的点并计算y为上下平行的x。如果它的实际值在计算值之间,那么它就算在线上。这是O(n ^ 3)。 代码:

public static void main(String[] args) {
    Point[] points = generatePoints(5);

    List<Set<Point>> lines = findLines(points,2,3);

    lines.forEach((line)->{
        System.out.println(Arrays.toString(line.toArray()));
    });

}


private static List<Set<Point>> findLines(Point[] points,int tolerance,int minNumberOfPoints) {

    List<Set<Point>> lines = new LinkedList<>();

    for(int i=0;i<points.length;i++){
        for(int j=i+1;j<points.length;j++){
            //check if that line was all ready found
            boolean hasBoth = false;
            for(Set<Point> line:lines){
                hasBoth =Boolean.logicalAnd(line.contains(points[i]),line.contains(points[j]));
                if(hasBoth)
                    break;
            }
            if(hasBoth)
                break;

            int x1 = points[i].getX();
            int y1 = points[i].getY();
            int x2 = points[j].getX();
            int y2 = points[j].getY();

            double k = (double)(y1-y2)/(double)(x1-x2);
            double l = y1-k*x1;

            //y = kx + l -> line
            //y1 = kx + l - tolerance -> lower parallel line
            //y2 = kx + l + tolerance -> upper parallel line
            //take a third point if for its x it gives a y3 where y1<=y3<=y2 then it should be part of the line

            Set<Point> line = new HashSet<>();
            line.add(points[i]);
            line.add(points[j]);

            for(int z=j+1;z<points.length;z++){
                int x3 = points[z].getX();
                int y3 = points[z].getY();

                double y1Line = k*x3+l-tolerance;
                double y2Line = k*x3+l+tolerance;
                if(y1Line<=y3 && y3<=y2Line)
                    line.add(points[z]);
            }
            lines.add(line);
        }
    }

    lines = lines.stream().filter((set)->{
        return set.size()>=minNumberOfPoints;
    }).collect(Collectors.toList());

    return lines;
}

private static Point[] generatePoints(int number) {
    Point[] points = new Point[number];
    Random r = new Random();
    for(int i=0;i<number;i++){
        points[i] = new Point(r.nextInt(10), r.nextInt(10));
    }
    return points;
}

private static class Point{
    private int x;
    private int y;
    public Point(int x,int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
    @Override
    public String toString() {
        return "("+x+","+y+")";
    }
}

答案 4 :(得分:0)

您可以使用Hough变换来检测线条。我在检测图像中的特征时经历了霍夫转换。它基本上使用线的极坐标来检测它们。虽然我认为opencv不符合你想要做的事情,但我仍然希望与你分享hough line检测页面,这非常清楚地解释了算法。

http://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html

我发现这个来源也很有用:

https://www.cs.sfu.ca/~hamarneh/ecopy/compvis1999_hough.pdf