Ejemplo n.º 1
0
    static bool so_seams_intersect(so_seam_t a, so_seam_t b)
    {
#if false
        // don't join intersected seams
        return(false);
#endif
        // compare bounding boxes first
        if (a.x_min > b.x_max || b.x_min >= a.x_max ||
            a.y_min > b.y_max || b.y_min >= a.y_max)
        {
            return(false);
        }

        // bounds intersect . check each individual texel for intersection
        if (a.texels.capacity > b.texels.capacity)         // swap so that we always loop over the smaller set
        {
            so_seam_t tmp = a;
            a = b;
            b = tmp;
        }

        for (int i = 0; i < a.texels.capacity; i++)
        {
            if (a.texels.texels[i].x != -1)
            {
                if (so_texel_set_contains(b.texels, a.texels.texels[i]))
                {
                    return(true);
                }
            }
        }
        return(false);
    }
Ejemplo n.º 2
0
    static void so_seams_in_place_merge(so_seam_t dst, so_seam_t src)
    {
        // expand bounding box
        dst.x_min = Mathf.Min(src.x_min, dst.x_min);
        dst.y_min = Mathf.Min(src.y_min, dst.y_min);
        dst.x_max = Mathf.Max(src.x_max, dst.x_max);
        dst.y_max = Mathf.Max(src.y_max, dst.y_max);

        // insert src elements
        so_texel_set_add(dst.texels, src.texels.texels, src.texels.count, src.texels.capacity);
        so_stitching_points_append(dst.stitchingPoints, src.stitchingPoints);
    }
Ejemplo n.º 3
0
    static void so_seam_add(so_seam_t seam, so_stitching_point_t point)
    {
        for (int side = 0; side < 2; side++)
        {
            for (int texel = 0; texel < 4; texel++)
            {
                so_texel_t t = point.sides[side].texels[texel];
                seam.x_min = Mathf.Min(t.x, seam.x_min);
                seam.y_min = Mathf.Min(t.y, seam.y_min);
                seam.x_max = Mathf.Max(t.x, seam.x_min);
                seam.y_max = Mathf.Max(t.y, seam.y_min);
            }
            so_texel_set_add(seam.texels, point.sides[side].texels, 4);
        }

        so_stitching_points_add(seam.stitchingPoints, point);
    }
Ejemplo n.º 4
0
    public static bool so_seam_optimize(so_seam_t seam, Color[] data, int w, int h, int c = 3, float lambda = 0.1f)
    {
        so_texel_set_t        texels          = seam.texels;
        so_stitching_points_t stitchingPoints = seam.stitchingPoints;

        int m = stitchingPoints.count;
        int n = texels.count;

        so_texel_t[] texelsFlat = new so_texel_t[n];
        for (int i = 0; i < n; i++)
        {
            texelsFlat[i] = new so_texel_t(0, 0);
        }

        float[] A = new float[(m + n) * 8];

        int[] AsparseIndices = new int[(m + n) * 8];

        float[] b = new float[m + n];

        float[] Atb = new float[n];

        float[] x = new float[n];

        for (int i = 0, j = 0; i < texels.capacity && j < n; i++)
        {
            if (texels.texels[i].x != -1)
            {
                texelsFlat[j++] = texels.texels[i];
            }
        }

        System.Array.Sort(texelsFlat, so_texel_cmp);

        int r = 0;

        for (int i = 0; i < m; i++)
        {
            int[] column0 = { 0, 0, 0, 0 };
            int[] column1 = { 0, 0, 0, 0 };
            bool  side0valid = false, side1valid = false;
            for (int k = 0; k < 4; k++)
            {
                so_texel_t t0 = stitchingPoints.points[i].sides[0].texels[k];
                so_texel_t t1 = stitchingPoints.points[i].sides[1].texels[k];
                column0[k] = System.Array.BinarySearch(texelsFlat, t0, so_texel_cmp);
                column1[k] = System.Array.BinarySearch(texelsFlat, t1, so_texel_cmp);

                if (column0[k] == -1)
                {
                    side0valid = false; break;
                }
                if (column1[k] == -1)
                {
                    side1valid = false; break;
                }

                // test for validity of stitching point
                for (int ci = 0; ci < c; ci++)
                {
                    side0valid |= data[t0.y * w + t0.x][ci] > 0.0f;
                    side1valid |= data[t1.y * w + t1.x][ci] > 0.0f;
                }
            }

            if (side0valid && side1valid)
            {
                for (int k = 0; k < 4; k++)
                {
                    A[r * 8 + k * 2 + 0] = stitchingPoints.points[i].sides[0].weights[k];
                    AsparseIndices[r * 8 + k * 2 + 0] = column0[k];
                    A[r * 8 + k * 2 + 1] = -stitchingPoints.points[i].sides[1].weights[k];
                    AsparseIndices[r * 8 + k * 2 + 1] = column1[k];
                }
                r++;
            }
        }

        m = r;

        // add error terms for deviation from original pixel value (scaled by lambda)
        for (int i = 0; i < n; i++)
        {
            A[(m + i) * 8] = lambda;
            AsparseIndices[(m + i) * 8 + 0] = i;
            AsparseIndices[(m + i) * 8 + 1] = -1;
        }

        so_sparse_entries_t AtA = so_matrix_At_times_A(A, AsparseIndices, 8, m + n, n);
        so_sparse_entries_t L   = so_matrix_cholesky_prepare(AtA, n);

        if (L.count == 0)
        {
            return(false);            // Cholesky decomposition failed
        }

        so_sparse_entries_t Lcols = new so_sparse_entries_t(L.count);

        for (int i = 0; i < L.count; i++)
        {
            so_sparse_matrix_add(Lcols, (L.entries[i].index % n) * n + (L.entries[i].index / n), L.entries[i].value);
        }
        so_sparse_matrix_sort(Lcols);

        // solve each color channel independently
        for (int ci = 0; ci < c; ci++)
        {
            for (int i = 0; i < n; i++)
            {
                b[m + i] = lambda * data[texelsFlat[i].y * w + texelsFlat[i].x][ci];
            }

            so_matrix_At_times_b(A, m + n, n, b, Atb, AsparseIndices, 8);
            so_matrix_cholesky_solve(L, Lcols, x, Atb, n);

            // write out results
            for (int i = 0; i < n; i++)
            {
                data[texelsFlat[i].y * w + texelsFlat[i].x][ci] = Mathf.Max(x[i], 0);
            }
        }

        return(true);
    }
Ejemplo n.º 5
0
    static void so_seams_add_seam(List <so_seam_t> seams, Vector2 a0, Vector2 a1, Vector2 b0, Vector2 b1, Color[] data, int w, int h, int c)
    {
        Vector2 s = new Vector2(w - 1, h - 1);

        a0 = Extensions.Multiply(a0, s);
        a1 = Extensions.Multiply(a1, s);
        b0 = Extensions.Multiply(b0, s);
        b1 = Extensions.Multiply(b1, s);
        Vector2 ad         = a1 - a0;
        Vector2 bd         = b1 - b0;
        float   l          = Mathf.Max(ad.magnitude, bd.magnitude);
        int     iterations = (int)(l * 5.0f);     // TODO: is this the best value?
        float   step       = 1.0f / iterations;

        so_seam_t currentSeam = new so_seam_t();

        currentSeam.x_min = w; currentSeam.y_min = h;
        currentSeam.x_max = 0; currentSeam.y_max = 0;

        // so_seam_alloc
        currentSeam.stitchingPoints = new so_stitching_points_t(iterations + 1);
        currentSeam.texels          = new so_texel_set_t();

        for (int i = 0; i <= iterations; i++)
        {
            float   t = i * step;
            Vector2 a = a0 + ad * t;
            Vector2 b = b0 + bd * t;
            // Kanglai: shouldn't be Round here
            int   ax = Mathf.FloorToInt(a.x), ay = Mathf.FloorToInt(a.y);
            int   bx = Mathf.FloorToInt(b.x), by = Mathf.FloorToInt(b.y);
            float au = a.x - ax, av = a.y - ay, nau = 1.0f - au, nav = 1.0f - av;
            float bu = b.x - bx, bv = b.y - by, nbu = 1.0f - bu, nbv = 1.0f - bv;

            so_texel_t ta0 = new so_texel_t(ax, ay);
            so_texel_t ta1 = new so_texel_t(Mathf.Min(ax + 1, w - 1), ay);
            so_texel_t ta2 = new so_texel_t(ax, Mathf.Min(ay + 1, h - 1));
            so_texel_t ta3 = new so_texel_t(Mathf.Min(ax + 1, w - 1), Mathf.Min(ay + 1, h - 1));

            so_texel_t tb0 = new so_texel_t(bx, by);
            so_texel_t tb1 = new so_texel_t(Mathf.Min(bx + 1, w - 1), by);
            so_texel_t tb2 = new so_texel_t(bx, Mathf.Min(by + 1, h - 1));
            so_texel_t tb3 = new so_texel_t(Mathf.Min(bx + 1, w - 1), Mathf.Min(by + 1, h - 1));

            /*
             * so_fill_with_closest(ta0.x, ta0.y, data, w, h, c);
             * so_fill_with_closest(ta1.x, ta1.y, data, w, h, c);
             * so_fill_with_closest(ta2.x, ta2.y, data, w, h, c);
             * so_fill_with_closest(ta3.x, ta3.y, data, w, h, c);
             *
             * so_fill_with_closest(tb0.x, tb0.y, data, w, h, c);
             * so_fill_with_closest(tb1.x, tb1.y, data, w, h, c);
             * so_fill_with_closest(tb2.x, tb2.y, data, w, h, c);
             * so_fill_with_closest(tb3.x, tb3.y, data, w, h, c);
             */
            so_stitching_point_t sp = new so_stitching_point_t();
            sp.sides[0].texels[0] = ta0;
            sp.sides[0].texels[1] = ta1;
            sp.sides[0].texels[2] = ta2;
            sp.sides[0].texels[3] = ta3;

            sp.sides[0].weights[0] = nau * nav;
            sp.sides[0].weights[1] = au * nav;
            sp.sides[0].weights[2] = nau * av;
            sp.sides[0].weights[3] = au * av;

            sp.sides[1].texels[0] = tb0;
            sp.sides[1].texels[1] = tb1;
            sp.sides[1].texels[2] = tb2;
            sp.sides[1].texels[3] = tb3;

            sp.sides[1].weights[0] = nbu * nbv;
            sp.sides[1].weights[1] = bu * nbv;
            sp.sides[1].weights[2] = nbu * bv;
            sp.sides[1].weights[3] = bu * bv;

            so_seam_add(currentSeam, sp);
        }
        so_seam_t dstSeam = null;

        for (int i = 0; i < seams.Count; i++)
        {
            so_seam_t seam = seams[i];
            // Kanglai: we put seams that intersects together
            if (so_seams_intersect(currentSeam, seam))
            {
                if (dstSeam == null)                 // found a seam that the edge is connected to . add current edge to that seam
                {
                    so_seams_in_place_merge(seam, currentSeam);
                    dstSeam = seam;
                }
                else                 // found another seam that the edge is connected to . merge those seams
                {
                    so_seams_in_place_merge(dstSeam, seam);

                    // remove current seam from seams
                    seams.Remove(seam);
                    i--;
                }
            }
        }
        if (dstSeam == null)         // did not find a seam that the edge is connected to . make a new one
        {
            seams.Add(currentSeam);
        }
    }