static bool so_texel_set_contains(so_texel_set_t set, so_texel_t texel) { int hash = so_texel_hash(texel, set.capacity); while (set.texels[hash].x != -1) // entries with same hash { if (set.texels[hash].x == texel.x && set.texels[hash].y == texel.y) { return(true); // texel is already in the set } hash = (hash + 1) % set.capacity; } return(false); }
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); }
static void so_texel_set_add(so_texel_set_t set, so_texel_t[] texels, int entries, int arrayLength = 0) { if (set.count + entries > set.capacity * 3 / 4) // leave some free space to avoid having many collisions { int newCapacity = set.capacity > 64 ? set.capacity * 2 : 64; while (set.count + entries > newCapacity * 3 / 4) { newCapacity *= 2; } so_texel_t[] newTexels = new so_texel_t[newCapacity]; for (int i = 0; i < newCapacity; i++) { newTexels[i] = new so_texel_t(-1, -1); } if (set.texels != null) { for (int i = 0; i < set.capacity; i++) // rehash all old texels { if (set.texels[i].x != -1) { int hash = so_texel_hash(set.texels[i], newCapacity); while (newTexels[hash].x != -1) // collisions { hash = (hash + 1) % newCapacity; } newTexels[hash] = set.texels[i]; } } } set.texels = newTexels; set.capacity = newCapacity; } if (arrayLength == 0) { arrayLength = entries; } for (int i = 0; i < arrayLength; i++) { if (texels[i].x != -1) { int hash = so_texel_hash(texels[i], set.capacity); while (set.texels[hash].x != -1) // collisions { if (set.texels[hash].x == texels[i].x && set.texels[hash].y == texels[i].y) { break; // texel is already in the set } hash = (hash + 1) % set.capacity; } if (set.texels[hash].x == -1) { set.texels[hash] = texels[i]; set.count++; } } } }