def test_lkm(): index = 1 scale = 0.2 epsilon = 1e-7 radius = 2 image_dir = "data" name = f"GT{index:02d}" image = load_image(f"{image_dir}/input_training_lowres/{name}.png", "rgb", scale, "bilinear") trimap = load_image( f"{image_dir}/trimap_training_lowres/Trimap1/{name}.png", "gray", scale, "nearest", ) L_lkm, diag_L_lkm = lkm_laplacian(image, epsilon=epsilon, radius=radius) L_cf = cf_laplacian(image, epsilon=epsilon, radius=radius) A_cf, b, c = make_linear_system(L_cf, trimap, return_c=True) def A_lkm(x): return L_lkm(x) + c * x inv_diag_A_lkm = 1.0 / (diag_L_lkm + c) def jacobi_lkm(r): return inv_diag_A_lkm * r jacobi_cf = jacobi(A_cf) lkm_callback = ProgressCallback() cf_callback = ProgressCallback() x_lkm = cg(A_lkm, b, M=jacobi_lkm) x_cf = cg(A_cf, b, M=jacobi_cf) difference = np.linalg.norm(x_lkm - x_cf) assert difference < 2e-4 assert abs(lkm_callback.n - cf_callback.n) <= 2
def test_preconditioners(): atol = 1e-6 index = 1 scale = 0.2 name = f"GT{index:02d}" # print(name) image_dir = "data" image = load_image(f"{image_dir}/input_training_lowres/{name}.png", "rgb", scale, "bilinear") trimap = load_image( f"{image_dir}/trimap_training_lowres/Trimap1/{name}.png", "gray", scale, "nearest", ) A, b = make_linear_system(cf_laplacian(image), trimap) preconditioners = [ ("no", lambda A: None), ("jacobi", lambda A: jacobi(A)), ("icholt", lambda A: ichol(A, max_nnz=500000)), ("vcycle", lambda A: vcycle(A, trimap.shape)), ] expected_iterations = { "no": 532, "jacobi": 250, "icholt": 3, "vcycle": 88, } for preconditioner_name, preconditioner in preconditioners: callback = CounterCallback() M = preconditioner(A) x = cg(A, b, M=M, atol=atol, rtol=0, maxiter=10000, callback=callback) r = b - A.dot(x) norm_r = np.linalg.norm(r) assert norm_r <= atol n_expected = expected_iterations[preconditioner_name] if callback.n > n_expected: print( "WARNING: Unexpected number of iterations. Expected %d, but got %d" % (n_expected, callback.n)) assert callback.n <= n_expected
def main(): print("loading images") size = (34, 22) size = (680, 440) image = np.array( Image.open("images/lemur.png").convert("RGB").resize( size, Image.BOX)) / 255.0 trimap = np.array( Image.open("images/lemur_trimap.png").convert("L").resize( size, Image.NEAREST)) / 255.0 is_fg = trimap == 1.0 is_bg = trimap == 0.0 is_known = is_fg | is_bg is_unknown = ~is_known b = 100.0 * is_fg.flatten() c = 100.0 * is_known.flatten() shape = trimap.shape h, w = shape L = cf_laplacian(image) cache = {} C = scipy.sparse.diags(c) build_cache_L(L, shape, cache) # If the trimap changes, simply call this function again with the new vector c build_cache_c(c, shape, cache) M = lambda x: vcycle_step(x, shape, cache) x = cg(lambda x: L.dot(x) + c * x, b, M=M, callback=ProgressCallback()) print("\nbaseline:") print("iteration 69 - 2.690681e-03 (0.00269068076571873623)") print() print("slight error due to discarding of C-offdiagonals") alpha = np.clip(x, 0, 1).reshape(h, w) import matplotlib.pyplot as plt for i, img in enumerate([image, trimap, alpha]): plt.subplot(1, 3, 1 + i) plt.imshow(img, cmap='gray') plt.axis('off') plt.show()
def main(): print("loading images") size = (34, 22) size = (680, 440) image = np.array( Image.open("images/lemur.png").convert("RGB").resize( size, Image.BOX)) / 255.0 trimap = np.array( Image.open("images/lemur_trimap.png").convert("L").resize( size, Image.NEAREST)) / 255.0 is_fg = trimap == 1.0 is_bg = trimap == 0.0 is_known = is_fg | is_bg is_unknown = ~is_known b = 100.0 * is_fg.flatten() c = 100.0 * is_known.flatten() shape = trimap.shape h, w = shape L = cf_laplacian(image) C = scipy.sparse.diags(c) A = L + C M = vcycle(A, (h, w)) x = cg(A, b, M=M, callback=ProgressCallback()) print("\nbaseline:") print("iteration 69 - 2.690681e-03 (0.00269068076571873623)") alpha = np.clip(x, 0, 1).reshape(h, w) import matplotlib.pyplot as plt for i, img in enumerate([image, trimap, alpha]): plt.subplot(1, 3, 1 + i) plt.imshow(img, cmap='gray') plt.axis('off') plt.show()
def compute_alpha(image, trimap, laplacian_name, is_fg, is_bg, is_known): laplacians = dict( (laplacian.__name__, laplacian) for laplacian in LAPLACIANS) atol = ATOL * np.sum(is_known) if laplacian_name == "lkm_laplacian": L_matvec, diag_L = lkm_laplacian(image) lambda_value = 100.0 c = lambda_value * is_known.ravel() b = lambda_value * is_fg.ravel() inv_diag_A = 1.0 / (diag_L + c) A = lambda x: L_matvec(x) + c * x # jacobi preconditioner for lkm_laplacian M = lambda x: inv_diag_A * x else: laplacian = laplacians[laplacian_name] A, b = make_linear_system(laplacian(image), trimap) preconditioner = { "knn_laplacian": jacobi, "rw_laplacian": jacobi, "cf_laplacian": ichol, "lbdm_laplacian": ichol, "uniform_laplacian": ichol, }[laplacian_name] M = preconditioner(A) x = cg(A, b, M=M, atol=atol) alpha = np.clip(x, 0, 1).reshape(trimap.shape) return alpha
def test_cg(): np.random.seed(0) atol = 1e-10 for n in [1, 5, 10]: x_true = np.random.rand(n) # make positive definite matrix A = np.random.rand(n, n) A += A.T + n * np.eye(n) b = A.dot(x_true) M_jacobi = np.diag(1.0 / np.diag(A)) def precondition(x): return M_jacobi.dot(x) for x0 in [None, np.random.rand(n)]: for M in [None, M_jacobi, precondition]: for callback in [None, CounterCallback(), ProgressCallback()]: x = cg(A, b, x0=x0, M=M, rtol=0, atol=atol, callback=callback) r = np.linalg.norm(A.dot(x) - b) assert np.linalg.norm(r) < 1e-10 if callback is not None: assert 0 < callback.n < 20
def build_solver(solver_name, A, Acsr, Acsc, Acoo, AL, b, atol, rtol): # Construct a solver from matrix A and vector b. if solver_name == "cg_icholt": from pymatting import cg, ichol M = ichol(A, discard_threshold=1e-3, shifts=[0.002]) return lambda: cg(A, b, M=M, atol=atol, rtol=0) if solver_name == "pyamg": import pyamg from pymatting import cg M = pyamg.smoothed_aggregation_solver(A).aspreconditioner() return lambda: cg(Acsr, b, M=M, atol=atol, rtol=0) if solver_name == "mumps": from solve_mumps import solve_mumps_coo, init_mpi, finalize_mpi init_mpi() return lambda: solve_mumps_coo( AL.data, AL.row, AL.col, b, is_symmetric=True) if solver_name == "petsc": from solve_petsc import solve_petsc_coo, init_petsc, finalize_petsc init_petsc() return lambda: solve_petsc_coo( Acoo.data, Acoo.row, Acoo.col, b, atol=atol, gamg_threshold=0.1) if solver_name == "amgcl": from solve_amgcl import solve_amgcl_csr return lambda: solve_amgcl_csr( Acsr.data, Acsr.indices, Acsr.indptr, b, atol=atol, rtol=0) if solver_name == "umfpack": # Alternatively: # return lambda: scipy.sparse.linalg.spsolve(Acsc, b, use_umfpack=True) import scikits.umfpack return lambda: scikits.umfpack.spsolve(A, b) if solver_name == "superlu": # Alternatively: # scipy.sparse.linalg.spsolve(A, b, use_umfpack=False) return lambda: scipy.sparse.linalg.splu(Acsc).solve(b) if solver_name == "eigen_cholesky": from solve_eigen import solve_eigen_cholesky_coo return lambda: solve_eigen_cholesky_coo(Acoo.data, Acoo.row, Acoo.col, b) if solver_name == "eigen_icholt": from solve_eigen import solve_eigen_icholt_coo # Choose shift hust large enough to not fail for given images # (might fail with larger/different images) initial_shift = 5e-4 return lambda: solve_eigen_icholt_coo(Acoo.data, Acoo.row, Acoo.col, b, rtol=rtol, initial_shift=initial_shift) raise ValueError(f"Solver {solver_name} does not exist.")
def solve_pyamg(A, b, atol): M = pyamg.smoothed_aggregation_solver(A).aspreconditioner() return cg(A, b, M=M, atol=atol, rtol=0)
def solve_cg_icholt(A, b, atol): M = ichol(A, discard_threshold=1e-3, shifts=[0.002]) return cg(A, b, M=M, atol=atol, rtol=0)
def main(): indices = 1 + np.arange(27) scale = 1.0 image_dir = "../data" info = {} laplacian_name = "lkm_laplacian" print(laplacian_name) errors = {} for index in indices: name = f"GT{index:02d}" print(name) image = load_image(f"{image_dir}/input_training_lowres/{name}.png", "rgb", scale, "bilinear") trimap = load_image(f"{image_dir}/trimap_training_lowres/Trimap1/{name}.png", "gray", scale, "bilinear") true_alpha = load_image(f"{image_dir}/gt_training_lowres/{name}.png", "gray", scale, "nearest") L_matvec, diag_L = lkm_laplacian(image) is_fg, is_bg, is_known, is_unknown = trimap_split(trimap) atol = 1e-7 * np.sum(is_known) lambda_value = 100.0 c = lambda_value * is_known b = lambda_value * is_fg inv_diag_A = 1.0 / (diag_L + c) def A_matvec(x): return L_matvec(x) + c * x def jacobi(x): return inv_diag_A * x x = cg(A_matvec, b, M=jacobi, atol=atol) alpha = np.clip(x, 0, 1).reshape(trimap.shape) difference_unknown = np.abs(alpha - true_alpha)[is_unknown.reshape(trimap.shape)] error = np.linalg.norm(difference_unknown) errors[str(index)] = error info[laplacian_name] = errors for laplacian in LAPLACIANS: laplacian_name = laplacian.__name__ print(laplacian_name) errors = {} for index in indices: name = f"GT{index:02d}" print(name) image = load_image(f"{image_dir}/input_training_lowres/{name}.png", "rgb", scale, "bilinear") trimap = load_image(f"{image_dir}/trimap_training_lowres/Trimap1/{name}.png", "gray", scale, "bilinear") true_alpha = load_image(f"{image_dir}/gt_training_lowres/{name}.png", "gray", scale, "nearest") A, b = make_linear_system(laplacian(image), trimap) is_fg, is_bg, is_known, is_unknown = trimap_split(trimap, flatten=False) atol = 1e-7 * np.sum(is_known) preconditioner = { "knn_laplacian": jacobi, "rw_laplacian": jacobi, "cf_laplacian": ichol, "lbdm_laplacian": ichol, "uniform_laplacian": ichol, }[laplacian_name] x = cg(A, b, M=preconditioner(A), atol=atol) alpha = np.clip(x, 0, 1).reshape(trimap.shape) difference_unknown = np.abs(alpha - true_alpha)[is_unknown] error = np.linalg.norm(difference_unknown) errors[str(index)] = error info[laplacian_name] = errors with open("results/laplacians.json", "w") as f: print(info) json.dump(info, f, indent=4)
def main(): print("loading images") mses = [] for idx in range(1, 28): image = np.array( Image.open(f"{DATASET_DIRECTORY}/input_training_lowres/GT%02d.png" % idx).convert("RGB")) / 255.0 trimap = np.array( Image.open( f"{DATASET_DIRECTORY}/trimap_training_lowres/Trimap1/GT%02d.png" % idx).convert("L")) / 255.0 alpha_gt = np.array( Image.open(f"{DATASET_DIRECTORY}/gt_training_lowres/GT%02d.png" % idx).convert("L")) / 255.0 is_fg = trimap == 1.0 is_bg = trimap == 0.0 is_known = is_fg | is_bg is_unknown = ~is_known b = 100.0 * is_fg.flatten() c = 100.0 * is_known.flatten() shape = trimap.shape h, w = shape L = cf_laplacian(image) cache = {} C = scipy.sparse.diags(c) build_cache_L(L, shape, cache) # If the trimap changes, simply call this function again with the new vector c build_cache_c(c, shape, cache) M = lambda x: vcycle_step(x, shape, cache) x = cg(lambda x: L.dot(x) + c * x, b, M=M, callback=ProgressCallback()) alpha = np.clip(x, 0, 1).reshape(h, w) difference = np.abs(alpha - alpha_gt) mse = np.mean(np.square(difference[is_unknown])) print("MSE:", mse) mses.append(mse) continue import matplotlib.pyplot as plt for i, img in enumerate([image, trimap, alpha]): plt.subplot(1, 3, 1 + i) plt.imshow(img, cmap='gray') plt.axis('off') plt.show() print("mean MSE:", np.mean(mses)) print() print("Expected:") print("mean MSE: 0.021856688900784647")
def test_lkm(): index = 1 scale = 0.2 atol = 1e-5 epsilon = 1e-7 radius = 2 image_dir = "data" errors = [] name = f"GT{index:02d}" # print(name) image = load_image( f"{image_dir}/input_training_lowres/{name}.png", "rgb", scale, "bilinear" ) trimap = load_image( f"{image_dir}/trimap_training_lowres/Trimap1/{name}.png", "gray", scale, "bilinear", ) true_alpha = load_image( f"{image_dir}/gt_training_lowres/{name}.png", "gray", scale, "nearest" ) L_lkm, diag_L_lkm = lkm_laplacian(image, epsilon=epsilon, radius=radius) L_cf = cf_laplacian(image, epsilon=epsilon, radius=radius) A_cf, b, c = make_linear_system(L_cf, trimap, return_c=True) def A_lkm(x): return L_lkm(x) + c * x inv_diag_A_lkm = 1.0 / (diag_L_lkm + c) def jacobi_lkm(r): return inv_diag_A_lkm * r jacobi_cf = jacobi(A_cf) lkm_callback = ProgressCallback() cf_callback = ProgressCallback() x_lkm = cg(A_lkm, b, M=jacobi_lkm) x_cf = cg(A_cf, b, M=jacobi_cf) if 0: # show result show_images( [x_lkm.reshape(trimap.shape), x_cf.reshape(trimap.shape),] ) difference = np.linalg.norm(x_lkm - x_cf) # print("norm(x_lkm - x_cf):") # print(difference) # print("iterations:") # print("lkm:", lkm_callback.n) # print("cf:", cf_callback.n) assert difference < 1e-5 assert abs(lkm_callback.n - cf_callback.n) <= 2