gpt4 book ai didi

用于在图中查找人脸的 Java 算法

转载 作者:行者123 更新时间:2023-12-04 02:26:42 24 4
gpt4 key购买 nike

我有一个我自己创建的平面图。我想找到这个图的面,但我找不到这样做的工作算法。到目前为止我所做的是使用一种算法来查找图中的所有循环,但这给了我所有可能的循环,我已经尝试过但没有找到一种方法来只对面部进行排序。我的一个想法是使用 Path2Ds contains 方法来查看另一个形状是否重叠,但由于面共享节点,这不起作用。下图展示了我想要的内容,之后的代码展示了我的可复制示例。
My graph and expected output

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class PolygonFinder {

// Graph modeled as list of edges
static int[][] graph
= {
{1, 2}, {1, 6}, {1, 5}, {2, 6},
{2, 3}, {3, 7}, {7, 4}, {3, 4},
{5, 4}, {6, 5}
};

static List<int[]> cycles = new ArrayList<>();

/**
* @param args
*/
public static void main(String[] args) {

for (int[] graph1 : graph) {
for (int j = 0; j < graph1.length; j++) {
findNewCycles(new int[]{graph1[j]});
}
}

cycles.stream().map(cy -> {
String s = "" + cy[0];
for (int i = 1; i < cy.length; i++) {
s += "," + cy[i];
}
return s;
}).forEachOrdered(s -> {
System.out.println(s);
});
}

static void findNewCycles(int[] path) {
int n = path[0];
int x;
int[] sub = new int[path.length + 1];

for (int[] graph1 : graph) {
for (int y = 0; y <= 1; y++) {
if (graph1[y] == n) {
x = graph1[(y + 1) % 2];
if (!visited(x, path)) // neighbor node not on path yet
{
sub[0] = x;
System.arraycopy(path, 0, sub, 1, path.length);
// explore extended path
findNewCycles(sub);
} else if ((path.length > 2) && (x == path[path.length - 1])) // cycle found
{
int[] p = normalize(path);
int[] inv = invert(p);
if (isNew(p) && isNew(inv)) {
cycles.add(p);
}
}
}
}
}
}

// check of both arrays have same lengths and contents
static Boolean equals(int[] a, int[] b) {
Boolean ret = (a[0] == b[0]) && (a.length == b.length);

for (int i = 1; ret && (i < a.length); i++) {
if (a[i] != b[i]) {
ret = false;
}
}

return ret;
}

// create a path array with reversed order
static int[] invert(int[] path) {
int[] p = new int[path.length];

for (int i = 0; i < path.length; i++) {
p[i] = path[path.length - 1 - i];
}

return normalize(p);
}

// rotate cycle path such that it begins with the smallest node
static int[] normalize(int[] path) {
int[] p = new int[path.length];
int x = smallest(path);
int n;

System.arraycopy(path, 0, p, 0, path.length);

while (p[0] != x) {
n = p[0];
System.arraycopy(p, 1, p, 0, p.length - 1);
p[p.length - 1] = n;
}

return p;
}

// compare path against known cycles
// return true, iff path is not a known cycle
static Boolean isNew(int[] path) {
Boolean ret = true;

for (int[] p : cycles) {
if (equals(p, path)) {
ret = false;
break;
}
}

return ret;
}

// return the int of the array which is the smallest
static int smallest(int[] path) {
int min = path[0];

for (int p : path) {
if (p < min) {
min = p;
}
}

return min;
}

// check if vertex n is contained in path
static Boolean visited(int n, int[] path) {
Boolean ret = false;

for (int p : path) {
if (p == n) {
ret = true;
break;
}
}

return ret;
}
}
运行上述代码后的结果是:
1,6,2
1,5,6,2
1,5,4,7,3,2
1,6,5,4,7,3,2
1,5,4,3,2
1,6,5,4,3,2
1,5,4,7,3,2,6
1,5,4,3,2,6
1,5,6
2,3,7,4,5,6
2,3,4,5,6
3,4,7
我解决这个问题的最佳尝试之一是使用以下代码。坐标来自顶部的图片。
    List<Polygon> polys = new LinkedList<>();
Polygon p1 = new Polygon();
p1.addPoint(new Point2D.Double(-4, 4));
p1.addPoint(new Point2D.Double(-1, 3));
p1.addPoint(new Point2D.Double(-1, 5));
Polygon p2 = new Polygon();
p2.addPoint(new Point2D.Double(-4, 4));
p2.addPoint(new Point2D.Double(0, -2));
p2.addPoint(new Point2D.Double(-1, 3));
p2.addPoint(new Point2D.Double(-1, 5));
Polygon p3 = new Polygon();
p3.addPoint(new Point2D.Double(-4, 4));
p3.addPoint(new Point2D.Double(0, -2));
p3.addPoint(new Point2D.Double(4, 1));
p3.addPoint(new Point2D.Double(2, 2));
p3.addPoint(new Point2D.Double(3, 4));
p3.addPoint(new Point2D.Double(-1, 5));
Polygon p4 = new Polygon();
p4.addPoint(new Point2D.Double(-4, 4));
p4.addPoint(new Point2D.Double(-1, 3));
p4.addPoint(new Point2D.Double(0, -2));
p4.addPoint(new Point2D.Double(4, 1));
p4.addPoint(new Point2D.Double(2, 2));
p4.addPoint(new Point2D.Double(3, 4));
p4.addPoint(new Point2D.Double(-1, 5));
Polygon p5 = new Polygon();
p5.addPoint(new Point2D.Double(-4, 4));
p5.addPoint(new Point2D.Double(0, -2));
p5.addPoint(new Point2D.Double(4, 1));
p5.addPoint(new Point2D.Double(3, 4));
p5.addPoint(new Point2D.Double(-1, 5));
Polygon p6 = new Polygon();
p6.addPoint(new Point2D.Double(-4, 4));
p6.addPoint(new Point2D.Double(-1, 3));
p6.addPoint(new Point2D.Double(0, -2));
p6.addPoint(new Point2D.Double(4, 1));
p6.addPoint(new Point2D.Double(3, 4));
p6.addPoint(new Point2D.Double(-1, 5));
Polygon p7 = new Polygon();
p7.addPoint(new Point2D.Double(-4, 4));
p7.addPoint(new Point2D.Double(0, -2));
p7.addPoint(new Point2D.Double(4, 1));
p7.addPoint(new Point2D.Double(2, 2));
p7.addPoint(new Point2D.Double(3, 4));
p7.addPoint(new Point2D.Double(-1, 5));
p7.addPoint(new Point2D.Double(-1, 3));
Polygon p8 = new Polygon();
p8.addPoint(new Point2D.Double(-4, 4));
p8.addPoint(new Point2D.Double(0, -2));
p8.addPoint(new Point2D.Double(4, 1));
p8.addPoint(new Point2D.Double(3, 4));
p8.addPoint(new Point2D.Double(-1, 5));
p8.addPoint(new Point2D.Double(-1, 3));
Polygon p9 = new Polygon();
p9.addPoint(new Point2D.Double(-4, 4));
p9.addPoint(new Point2D.Double(0, -2));
p9.addPoint(new Point2D.Double(-1, 3));
Polygon p10 = new Polygon();
p10.addPoint(new Point2D.Double(-1, 5));
p10.addPoint(new Point2D.Double(3, 4));
p10.addPoint(new Point2D.Double(2, 2));
p10.addPoint(new Point2D.Double(4, 1));
p10.addPoint(new Point2D.Double(0, -2));
p10.addPoint(new Point2D.Double(-1, 3));
Polygon p11 = new Polygon();
p11.addPoint(new Point2D.Double(-1, 5));
p11.addPoint(new Point2D.Double(3, 4));
p11.addPoint(new Point2D.Double(4, 1));
p11.addPoint(new Point2D.Double(0, -2));
p11.addPoint(new Point2D.Double(-1, 3));
Polygon p12 = new Polygon();
p12.addPoint(new Point2D.Double(3, 4));
p12.addPoint(new Point2D.Double(4, 1));
p12.addPoint(new Point2D.Double(2, 2));
polys.add(p1);
polys.add(p2);
polys.add(p3);
polys.add(p4);
polys.add(p5);
polys.add(p6);
polys.add(p7);
polys.add(p8);
polys.add(p9);
polys.add(p10);
polys.add(p11);
polys.add(p12);
Set<Integer> toRemove = new HashSet<>();
for (Polygon polyI : polys) {
for (Polygon polyJ : polys) {
if (polyI.equals(polyJ)) {
continue;
}
if (polyI.contains(polyJ)) {
toRemove.add(polys.indexOf(polyI));
}
}
}
List<Integer> list = new LinkedList<>(toRemove);
Collections.sort(list);
Collections.reverse(list);
list.forEach((t) -> {
polys.remove(t.intValue());
});

System.out.println("");
polys.forEach((t) -> {
System.out.println(t.getPoints());
});
此处列出了使用的多边形方法。
@Override
public boolean contains(Point2D point) {
return getPath().contains(point);
}

@Override
public boolean contains(IPolygon polygon) {
List<Point2D> p2Points = polygon.getPoints();
for (Point2D point : p2Points) {
if (getPath().contains(point)) {
if (!points.contains(point)) {
return true;
}
}
}
return false;
}

private Path2D getPath() {
Path2D path = new Path2D.Double();
path.moveTo(points.get(0).getX(), points.get(0).getY());
for (int i = 1; i < points.size(); i++) {
path.lineTo(points.get(i).getX(), points.get(i).getY());
}
path.closePath();
return path;
}
这段代码给了我下面的结果,不需要第 2-4 个。
[Point2D.Double[-4.0, 4.0], Point2D.Double[-1.0, 3.0], Point2D.Double[-1.0, 5.0]]
[Point2D.Double[-4.0, 4.0], Point2D.Double[0.0, -2.0], Point2D.Double[-1.0, 3.0], Point2D.Double[-1.0, 5.0]]
[Point2D.Double[-4.0, 4.0], Point2D.Double[-1.0, 3.0], Point2D.Double[0.0, -2.0], Point2D.Double[4.0, 1.0], Point2D.Double[2.0, 2.0], Point2D.Double[3.0, 4.0], Point2D.Double[-1.0, 5.0]]
[Point2D.Double[-4.0, 4.0], Point2D.Double[0.0, -2.0], Point2D.Double[4.0, 1.0], Point2D.Double[2.0, 2.0], Point2D.Double[3.0, 4.0], Point2D.Double[-1.0, 5.0], Point2D.Double[-1.0, 3.0]]
[Point2D.Double[-4.0, 4.0], Point2D.Double[0.0, -2.0], Point2D.Double[-1.0, 3.0]]
[Point2D.Double[-1.0, 5.0], Point2D.Double[3.0, 4.0], Point2D.Double[2.0, 2.0], Point2D.Double[4.0, 1.0], Point2D.Double[0.0, -2.0], Point2D.Double[-1.0, 3.0]]
[Point2D.Double[3.0, 4.0], Point2D.Double[4.0, 1.0], Point2D.Double[2.0, 2.0]]

最佳答案

  • 对于每条边,获取边顶点嵌入中的坐标,并使用它们使用三角法计算边的角度。
    例如,从 (x1, y1) 到 (x2, y2) 从正 x 轴逆时针测量的角度由 Math.atan2(y2-y1,x2-x1) 给出。
  • 对于每个顶点,通过按角度对边进行排序来创建循环边排序。这可以存储为数组,也可以使用循环列表数据结构。
  • 选择一条边,跟随它到一个相邻的顶点,然后跟随下一个相邻的顺时针边,重复跟随边到下一个顶点,然后下一个顺时针边,直到你回到起始边;那么你已经找到了图形的一个面。
  • 重复步骤 3,选择一条未访问的边或与前一条相反方向的已访问边,然后沿相同的顺时针方向沿着它找到下一个面。重复此操作,直到所有边都被访问了两次(每个方向一次),然后您就找到了所有的面。

  • 在 Java 中,这将是:
    import java.awt.geom.Point2D;
    import java.awt.Polygon;
    import java.util.ArrayList;
    import java.util.Comparator;
    import java.util.stream.Collectors;
    import java.text.MessageFormat;

    public class GraphFaces
    {
    static class Vertex
    {
    final int index;
    final Point2D point;
    final ArrayList<Edge> outboundEdges = new ArrayList<>();


    public Vertex( final int index, final Point2D point )
    {
    this.index = index;
    this.point = point;
    }

    public void addEdge( final Edge edge )
    {
    this.outboundEdges.add( edge );
    }

    public void sortEdges()
    {
    this.outboundEdges.sort((e1,e2)->Double.compare(e1.angle,e2.angle));

    Edge prev = this.outboundEdges.get(this.outboundEdges.size() - 1);
    for ( final Edge edge: this.outboundEdges )
    {
    edge.setNextEdge( prev );
    prev = edge;
    }
    }

    @Override
    public String toString()
    {
    return Integer.toString(this.index);
    // return MessageFormat.format("({0},{1})",this.point.getX(),this.point.getY());
    }
    }

    static class Edge
    {
    final Vertex from;
    final Vertex to;
    final double angle;
    boolean visited = false;
    Edge next = null;
    Edge reverse = null;

    public Edge( final Vertex from, final Vertex to )
    {
    this.from = from;
    this.to = to;
    this.angle = Math.atan2(to.point.getY() - from.point.getY(), to.point.getX() - from.point.getX());
    from.addEdge( this );
    }

    public Vertex getFrom()
    {
    return this.from;
    }

    public Vertex getTo()
    {
    return this.to;
    }

    public void setNextEdge( final Edge edge )
    {
    this.next = edge;
    }

    public void setReverseEdge( final Edge edge )
    {
    this.reverse = edge;
    }

    @Override
    public String toString()
    {
    return MessageFormat.format("{0} -> {1}", this.from, this.to);
    }
    }

    public static void main(final String[] args)
    {
    final Vertex[] vertices = {
    new Vertex( 1, new Point2D.Double(-4,+4) ),
    new Vertex( 2, new Point2D.Double(-1,+5) ),
    new Vertex( 3, new Point2D.Double(+3,+4) ),
    new Vertex( 4, new Point2D.Double(+4,+1) ),
    new Vertex( 5, new Point2D.Double(+0,-2) ),
    new Vertex( 6, new Point2D.Double(-1,+3) ),
    new Vertex( 7, new Point2D.Double(+2,+2) )
    };

    final int[][] graph = {
    {1, 2}, {1, 6}, {1, 5}, {2, 6}, {2, 3}, {3, 7}, {7, 4}, {3, 4}, {5, 4}, {6, 5}
    };

    final Edge[] edges = new Edge[2 * graph.length];

    for ( int i = 0; i < graph.length; i++ )
    {
    final Vertex from = vertices[graph[i][0]-1];
    final Vertex to = vertices[graph[i][1]-1];
    edges[2*i] = new Edge( from, to );
    edges[2*i+1] = new Edge( to, from );

    edges[2*i].setReverseEdge(edges[2*i+1]);
    edges[2*i+1].setReverseEdge(edges[2*i]);
    }


    for ( final Vertex vertex: vertices )
    {
    vertex.sortEdges();
    }

    final ArrayList<ArrayList<Edge>> faces = new ArrayList<>();
    for ( final Edge edge: edges )
    {
    if ( edge.visited )
    {
    continue;
    }
    final ArrayList<Edge> face = new ArrayList<>();
    faces.add( face );
    Edge e = edge;
    do
    {
    face.add(e);
    e.visited = true;
    e = e.reverse.next;
    }
    while (e != edge);

    System.out.println( face.stream().map(Edge::getFrom).collect(Collectors.toList()) );
    }
    }
    }
    哪些输出:
    [1, 2, 3, 4, 5]
    [2, 1, 6]
    [6, 1, 5]
    [2, 6, 5, 4, 7, 3]
    [3, 7, 4]

    注意:这包括图形的外表面。
    或者,如果您想: 测试图形的平面性;生成(双连通)图的所有可能嵌入;并为这些嵌入中的一个(或多个)生成循环边排序,然后您可以使用博士论文 Planarity Testing by Path Addition ,它在附录中包含完整的 Java 源代码。

    关于用于在图中查找人脸的 Java 算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67097270/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com