通过Renderscript加速处理Low Poly

时间:2016-09-08 03:51:57

标签: java android bitmap renderscript

什么是低聚?

Low Poly wiki

德洛奈

我在java中实现了Delaunay算法;但它很慢。在我的电脑中,将位图处理为低多边形大约需要4-9秒。 Android手机中的差很多。如果我调整输入位图的大小,它甚至需要大约1-2分钟。

实施

 final class Delaunay {


private static int[][] supertriangle(List<int[]> vertices) {
    int xMin = Integer.MAX_VALUE;
    int yMin = Integer.MAX_VALUE;
    int xMax = Integer.MIN_VALUE;
    int yMax = Integer.MIN_VALUE;

    float dx, dy, dmax, xmid, ymid;


    for (int i = vertices.size() - 1; i >= 0; i--) {
        int[] p = vertices.get(i);
        if (p[0] < xMin) xMin = p[0];
        if (p[0] > xMax) xMax = p[0];
        if (p[1] < yMin) yMin = p[1];
        if (p[1] > yMax) yMax = p[1];
    }

    dx = xMax - xMin;
    dy = yMax - yMin;

    dmax = Math.max(dx, dy);

    xmid = (xMin + dx * 0.5f);
    ymid = (yMin + dy * 0.5f);

    return new int[][]{{(int) (xmid - 20 * dmax), (int) (ymid - dmax)},
            {(int) xmid, (int) (ymid + 20 * dmax)},
            {(int) (xmid + 20 * dmax), (int) (ymid - dmax)}};
}

private static Circumcircle circumcircle(List<int[]> vertices, int i, int j, int k) {
    int x1 = vertices.get(i)[0];
    int y1 = vertices.get(i)[1];
    int x2 = vertices.get(j)[0];
    int y2 = vertices.get(j)[1];
    int x3 = vertices.get(k)[0];
    int y3 = vertices.get(k)[1];


    int fabsy1y2 = Math.abs(y1 - y2);
    int fabsy2y3 = Math.abs(y2 - y3);

    float xc, yc, m1, m2, mx1, mx2, my1, my2, dx, dy;


    if (fabsy1y2 == 0) {
        m2 = -((float) (x3 - x2) / (y3 - y2));
        mx2 = (x2 + x3) / 2f;
        my2 = (y2 + y3) / 2f;
        xc = (x2 + x1) / 2f;
        yc = m2 * (xc - mx2) + my2;
    } else if (fabsy2y3 == 0) {
        m1 = -((float) (x2 - x1) / (y2 - y1));
        mx1 = (x1 + x2) / 2f;
        my1 = (y1 + y2) / 2f;
        xc = (x3 + x2) / 2f;
        yc = m1 * (xc - mx1) + my1;
    } else {
        m1 = -((float) (x2 - x1) / (y2 - y1));
        m2 = -((float) (x3 - x2) / (y3 - y2));
        mx1 = (x1 + x2) / 2f;
        mx2 = (x2 + x3) / 2f;
        my1 = (y1 + y2) / 2f;
        my2 = (y2 + y3) / 2f;
        xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
        yc = (fabsy1y2 > fabsy2y3) ?
                m1 * (xc - mx1) + my1 :
                m2 * (xc - mx2) + my2;
    }

    dx = x2 - xc;
    dy = y2 - yc;

    return new Circumcircle(i, j, k, xc, yc, (dx * dx + dy * dy));
}

private static void dedup(ArrayList<Integer> edges) {
    int a, b, m, n;
    for (int j = edges.size(); j > 0; ) {
        while (j > edges.size()) {
            j--;
        }
        if (j <= 0) {
            break;
        }
        b = edges.get(--j);
        a = edges.get(--j);

        for (int i = j; i > 0; ) {
            n = edges.get(--i);
            m = edges.get(--i);

            if ((a == m && b == n) || (a == n && b == m)) {
                if (j + 1 < edges.size())
                    edges.remove(j + 1);
                edges.remove(j);
                if (i + 1 < edges.size())
                    edges.remove(i + 1);
                edges.remove(i);
                break;
            }
        }
    }
}

static List<Integer> triangulate(final List<int[]> vertices) {
    int n = vertices.size();

    if (n < 3) {
        return new ArrayList<>();
    }

    Integer[] indices = new Integer[n];

    for (int i = n - 1; i >= 0; i--) {
        indices[i] = i;
    }


    Arrays.sort(indices, new Comparator<Integer>() {
        @Override
        public int compare(Integer lhs, Integer rhs) {
            return vertices.get(rhs)[0] - vertices.get(lhs)[0];
        }
    });
    int[][] st = supertriangle(vertices);

    vertices.add(st[0]);
    vertices.add(st[1]);
    vertices.add(st[2]);

    ArrayList<Circumcircle> open = new ArrayList<>();
    open.add(circumcircle(vertices, n, n + 1, n + 2));

    ArrayList<Circumcircle> closed = new ArrayList<>();

    ArrayList<Integer> edges = new ArrayList<>();

    for (int i = indices.length - 1; i >= 0; i--) {

        int c = indices[i];

        for (int j = open.size() - 1; j >= 0; j--) {

            Circumcircle cj = open.get(j);
            int[] vj = vertices.get(c);

            float dx = vj[0] - cj.x;
            float dy = vj[1] - cj.y;

            if (dx > 0 && dx * dx + dy * dy > cj.r) {
                closed.add(cj);
                open.remove(j);
                continue;
            }


            if (dx * dx + dy * dy - cj.r > 0) {
                continue;
            }

            edges.add(cj.i);
            edges.add(cj.j);
            edges.add(cj.j);
            edges.add(cj.k);
            edges.add(cj.k);
            edges.add(cj.i);

            open.remove(j);
        }

        dedup(edges);

        for (int j = edges.size(); j > 0; ) {
            int b = edges.get(--j);
            int a = edges.get(--j);

            int x1 = vertices.get(a)[0];
            int y1 = vertices.get(a)[1];
            int x2 = vertices.get(b)[0];
            int y2 = vertices.get(b)[1];
            int x3 = vertices.get(c)[0];
            int y3 = vertices.get(c)[1];

            boolean hasCircumcircle = true;
            if ((x1==x2)&&(x1==x3) || ((y1==y2)&&(y1==y3))){
                hasCircumcircle = false;
            }
            if (hasCircumcircle) {
                open.add(circumcircle(vertices, a, b, c));
            }
        }

        edges.clear();

    }

    for (int i = open.size() - 1; i >= 0; i--) {
        closed.add(open.get(i));
    }

    open.clear();

    ArrayList<Integer> out = new ArrayList<>();

    for (int i = 0; i <closed.size(); i++) {
        Circumcircle ci = closed.get(i);
        if (ci.i < n && ci.j < n && ci.k < n) {
            out.add(ci.i);
            out.add(ci.j);
            out.add(ci.k);
        }
    }
    return out;
}

private static class Circumcircle {
    public int i, j, k;
    float x, y, r;

    public Circumcircle(int i, int j, int k, float x, float y, float r) {
        this.i = i;
        this.j = j;
        this.k = k;
        this.x = x;
        this.y = y;
        this.r = r;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Circumcircle){
            Circumcircle circumcircle = (Circumcircle) obj;
            if (x==circumcircle.x && y==circumcircle.y && r==circumcircle.r)
                return true;
        }
        return super.equals(obj);
    }
}


}

C中的Delaunay图书馆

delaunay

这个库是用C语言编写的。所以我认为它比java快。

我的问题

我想使用RenderScript来加工处理。如何输入一些点并获得三角形(只是输入点的索引)?

1 个答案:

答案 0 :(得分:0)

摘要:您至少应该尝试使用C版本来查看它的效果。

RenderScript是关于并行化问题的,因此CPU或GPU上的许多不同工作单元都可以处理数据。这意味着您希望在RenderScript中实现的算法必须最小化循环和条件。只看上面的代码就会显示一些循环和if语句在我看来并不能很好地移植到RenderScript。

快速搜索显示了许多关于并行化Delaunay的学术论文,所以尽管有可能你需要研究对你的输入集合有意义的东西或者什么是可接受的权衡。