forked from Tobias-Fischer/rt_gene
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpoissonblending.py
executable file
·92 lines (79 loc) · 3.21 KB
/
poissonblending.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
# Original code from https://github.com/parosky/poissonblending
import numpy as np
import scipy.sparse
import pyamg
# pre-process the mask array so that uint64 types from opencv.imread can be adapted
def prepare_mask(mask):
if type(mask[0][0]) is np.ndarray:
result = np.ndarray((mask.shape[0], mask.shape[1]), dtype=np.uint8)
for i in range(mask.shape[0]):
for j in range(mask.shape[1]):
if sum(mask[i][j]) > 0:
result[i][j] = 1
else:
result[i][j] = 0
mask = result
return mask
def blend(img_target, img_source, img_mask, offset=(0, 0)):
# compute regions to be blended
region_source = (
max(-offset[0], 0),
max(-offset[1], 0),
min(img_target.shape[0] - offset[0], img_source.shape[0]),
min(img_target.shape[1] - offset[1], img_source.shape[1]))
region_target = (
max(offset[0], 0),
max(offset[1], 0),
min(img_target.shape[0], img_source.shape[0] + offset[0]),
min(img_target.shape[1], img_source.shape[1] + offset[1]))
region_size = (region_source[2] - region_source[0], region_source[3] - region_source[1])
# clip and normalize mask image
img_mask = img_mask[region_source[0]:region_source[2], region_source[1]:region_source[3]]
img_mask = prepare_mask(img_mask)
img_mask[img_mask == 0] = False
img_mask[img_mask != False] = True
# create coefficient matrix
A = scipy.sparse.identity(np.prod(region_size), format='lil')
for y in range(region_size[0]):
for x in range(region_size[1]):
if img_mask[y, x]:
index = x + y * region_size[1]
A[index, index] = 4
if index + 1 < np.prod(region_size):
A[index, index + 1] = -1
if index - 1 >= 0:
A[index, index - 1] = -1
if index + region_size[1] < np.prod(region_size):
A[index, index + region_size[1]] = -1
if index - region_size[1] >= 0:
A[index, index - region_size[1]] = -1
A = A.tocsr()
# create poisson matrix for b
P = pyamg.gallery.poisson(img_mask.shape)
# for each layer (ex. RGB)
for num_layer in range(img_target.shape[2]):
# get subimages
t = img_target[region_target[0]:region_target[2], region_target[1]:region_target[3], num_layer]
s = img_source[region_source[0]:region_source[2], region_source[1]:region_source[3], num_layer]
t = t.flatten()
s = s.flatten()
# create b
b = P * s
for y in range(region_size[0]):
for x in range(region_size[1]):
if not img_mask[y, x]:
index = x + y * region_size[1]
b[index] = t[index]
# solve Ax = b
x = pyamg.solve(A, b, verb=False, tol=1e-10)
# assign x to target image
x = np.reshape(x, region_size)
x[x > 255] = 255
x[x < 0] = 0
x = np.array(x, img_target.dtype)
img_target[region_target[0]:region_target[2], region_target[1]:region_target[3], num_layer] = x
return img_target