Beispiel #1
0
    static void so_sparse_matrix_add(so_sparse_entries_t matrix, int index, float value)
    {
        if (matrix.count == matrix.capacity)
        {
            int newCapacity = matrix.capacity * 2;
            if (newCapacity < 64)
            {
                newCapacity = 64;
            }
            so_sparse_entry_t[] newEntries = new so_sparse_entry_t[newCapacity];
            for (int i = 0; i < matrix.count; i++)
            {
                newEntries[i] = matrix.entries[i];
            }
            for (int i = matrix.count; i < newCapacity; i++)
            {
                newEntries[i] = new so_sparse_entry_t(-1, 0);
            }
            matrix.entries  = newEntries;
            matrix.capacity = newCapacity;
        }

        int entryIndex = matrix.count++;

        matrix.entries[entryIndex].index = index;
        matrix.entries[entryIndex].value = value;
    }
Beispiel #2
0
    static void so_matrix_cholesky_solve(so_sparse_entries_t Lrows, so_sparse_entries_t Lcols, float[] x, float[] b, int n)
    {
        float[] y = new float[n];

        // L * y = b
        int Lindex = 0;

        for (int i = 0; i < n; i++)
        {
            float sum = b[i];
            while (Lindex < Lrows.count && Lrows.entries[Lindex].index < i * (n + 1))
            {
                sum -= Lrows.entries[Lindex].value * y[Lrows.entries[Lindex].index - i * n];
                ++Lindex;
            }
            Debug.Assert(Lrows.entries[Lindex].index == i * (n + 1));
            y[i] = sum / Lrows.entries[Lindex].value;
            ++Lindex;
        }

        // L' * x = y
        Lindex = Lcols.count - 1;
        for (int i = n - 1; i >= 0; i--)
        {
            float sum = y[i];
            while (Lindex >= 0 && Lcols.entries[Lindex].index > i * (n + 1))
            {
                sum -= Lcols.entries[Lindex].value * x[Lcols.entries[Lindex].index - i * n];
                --Lindex;
            }
            Debug.Assert(Lcols.entries[Lindex].index == i * (n + 1));
            x[i] = sum / Lcols.entries[Lindex].value;
            --Lindex;
        }
    }
Beispiel #3
0
    static so_sparse_entry_t so_sparse_entry_set_get_or_add(so_sparse_entries_t set, int index)
    {
        if (set.count + 1 > set.capacity * 3 / 4)         // leave some free space to avoid having many collisions
        {
            int newCapacity = set.capacity >= 64 ? set.capacity * 2 : 64;
            so_sparse_entry_t[] newEntries = new so_sparse_entry_t[newCapacity];
            for (int i = 0; i < newCapacity; i++)
            {
                newEntries[i] = new so_sparse_entry_t(-1, 0);
            }

            for (int i = 0; i < set.capacity; i++)             // rehash all old entries
            {
                if (set.entries[i].index != -1)
                {
                    int hash_ = so_sparse_entry_hash(set.entries[i].index, newCapacity);
                    while (newEntries[hash_].index != -1)                     // collisions
                    {
                        hash_ = (hash_ + 1) % newCapacity;
                    }
                    newEntries[hash_] = set.entries[i];
                }
            }
            set.entries  = newEntries;
            set.capacity = newCapacity;
        }

        int hash = so_sparse_entry_hash(index, set.capacity);

        while (set.entries[hash].index != -1)         // collisions
        {
            if (set.entries[hash].index == index)
            {
                return(set.entries[hash]);                // entry is already in the set
            }
            hash = (hash + 1) % set.capacity;
        }

        if (set.entries[hash].index == -1)         // make new entry
        {
            set.entries[hash].index = index;
            set.entries[hash].value = 0.0f;
            set.count++;
            return(set.entries[hash]);
        }

        Debug.Assert(false);
        return(null);        // shouldn't happen
    }
Beispiel #4
0
    static so_sparse_entries_t so_matrix_At_times_A(float[] A, int[] sparseIndices, int maxRowIndices, int m, int n)
    {
        so_sparse_entries_t AtA = new so_sparse_entries_t((n / 16) * (n / 16));

        // compute lower left triangle only since the result is symmetric
        for (int k = 0; k < m; k++)
        {
            int srcPtr   = k * maxRowIndices;
            int indexPtr = k * maxRowIndices;
            for (int i = 0; i < maxRowIndices; i++)
            {
                int index_i = sparseIndices[indexPtr + i];
                if (index_i < 0)
                {
                    break;
                }
                float v = A[srcPtr + i];
                //float *dstPtr = AtA + index_i * n;
                for (int j = 0; j < maxRowIndices; j++)
                {
                    int index_j = sparseIndices[indexPtr + j];
                    if (index_j < 0)
                    {
                        break;
                    }
                    //dstPtr[index_j] += v * srcPtr[j];
                    int index = index_i * n + index_j;

                    so_sparse_entry_t entry = so_sparse_entry_set_get_or_add(AtA, index);
                    entry.value += v * A[srcPtr + j];
                }
            }
        }

        // compaction step (make a compact array from the scattered hash set values)
        for (int i = 0, j = 0; i < AtA.capacity; i++)
        {
            if (AtA.entries[i].index != -1)
            {
                AtA.entries[j++] = AtA.entries[i];
            }
        }

        // sort by index . this is a sparse matrix now
        so_sparse_matrix_sort(AtA);

        return(AtA);
    }
Beispiel #5
0
    static bool so_sparse_matrix_advance_to_index(so_sparse_entries_t matrix, ref int position, int index, ref float outValue)
    {
        int localPosition = position;

        while (localPosition < matrix.count && matrix.entries[localPosition].index < index)
        {
            ++localPosition;
        }
        position = localPosition;

        if (localPosition < matrix.count && matrix.entries[localPosition].index == index)
        {
            outValue = matrix.entries[localPosition].value;
            return(true);
        }

        return(false);
    }
Beispiel #6
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);
    }
Beispiel #7
0
    static so_sparse_entries_t so_matrix_cholesky_prepare(so_sparse_entries_t AtA, int n)
    {
        // dense
        //for (int i = 0; i < n; i++)
        //{
        //	float *a = L + i * n;
        //	for (int j = 0; j <= i; j++)
        //	{
        //		float *b = L + j * n;
        //		float sum = A[i * n + j];// + (i == j ? 0.0001 : 0.0); // some regularization
        //		for (int k = 0; k < j; k++)
        //			sum -= a[k] * b[k];
        //		if (i > j)
        //			a[j] = sum / b[j];
        //		else // i == j
        //		{
        //			if (sum <= 0.0)
        //				return false;
        //			a[i] = sqrtf(sum);
        //		}
        //	}
        //}

        // sparse
        int[]   indices_i = new int[n];
        float[] row_i     = new float[n];
        float[] invDiag   = new float[n];

        so_sparse_entries_t L = new so_sparse_entries_t((n / 16) * (n / 16));

        int AtAindex = 0;

        for (int i = 0; i < n; i++)
        {
            int index_i_count = 0;

            int row_j_index = 0;
            for (int j = 0; j <= i; j++)
            {
                //float sum = A[i * n + j]; // + (i == j ? 0.0001 : 0.0); // regularization
                int   index = i * n + j;
                float sum   = 0.0f;
                so_sparse_matrix_advance_to_index(AtA, ref AtAindex, index, ref sum);

                for (int k = 0; k < index_i_count; k++)
                {
                    int   index_i = indices_i[k];
                    float Lvalue  = 0;
                    if (so_sparse_matrix_advance_to_index(L, ref row_j_index, j * n + index_i, ref Lvalue))
                    {
                        sum -= row_i[index_i] * Lvalue;
                    }
                }

                if (i == j)
                {
                    if (sum <= 0.0f)
                    {
                        return(L);
                    }
                    invDiag[i] = 1.0f / Mathf.Sqrt(sum);
                }

                if (Mathf.Abs(sum) > 0.00001f)
                {
                    row_i[j] = sum * invDiag[j];
                    indices_i[index_i_count++] = j;
                    so_sparse_matrix_add(L, index, row_i[j]);
                }
                else
                {
                    row_i[j] = 0.0f;
                }
            }
        }

        return(L);
    }
Beispiel #8
0
 static void so_sparse_matrix_sort(so_sparse_entries_t matrix)
 {
     System.Array.Sort(matrix.entries, 0, matrix.count, so_sparse_entry_cmp);
 }