File size: 5,165 Bytes
d4b77ac |
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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
import numpy as np
import cv2
from scipy import sparse
from scipy.sparse.linalg import spsolve
# Laplacian filling
def regionfill(I, mask, factor=1.0):
if np.count_nonzero(mask) == 0:
return I.copy()
resize_mask = cv2.resize(
mask.astype(float), (0, 0), fx=factor, fy=factor) > 0
resize_I = cv2.resize(I.astype(float), (0, 0), fx=factor, fy=factor)
maskPerimeter = findBoundaryPixels(resize_mask)
regionfillLaplace(resize_I, resize_mask, maskPerimeter)
resize_I = cv2.resize(resize_I, (I.shape[1], I.shape[0]))
resize_I[mask == 0] = I[mask == 0]
return resize_I
def findBoundaryPixels(mask):
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
maskDilated = cv2.dilate(mask.astype(float), kernel)
return (maskDilated > 0) & (mask == 0)
def regionfillLaplace(I, mask, maskPerimeter):
height, width = I.shape
rightSide = formRightSide(I, maskPerimeter)
# Location of mask pixels
maskIdx = np.where(mask)
# Only keep values for pixels that are in the mask
rightSide = rightSide[maskIdx]
# Number the mask pixels in a grid matrix
grid = -np.ones((height, width))
grid[maskIdx] = range(0, maskIdx[0].size)
# Pad with zeros to avoid "index out of bounds" errors in the for loop
grid = padMatrix(grid)
gridIdx = np.where(grid >= 0)
# Form the connectivity matrix D=sparse(i,j,s)
# Connect each mask pixel to itself
i = np.arange(0, maskIdx[0].size)
j = np.arange(0, maskIdx[0].size)
# The coefficient is the number of neighbors over which we average
numNeighbors = computeNumberOfNeighbors(height, width)
s = numNeighbors[maskIdx]
# Now connect the N,E,S,W neighbors if they exist
for direction in ((-1, 0), (0, 1), (1, 0), (0, -1)):
# Possible neighbors in the current direction
neighbors = grid[gridIdx[0] + direction[0], gridIdx[1] + direction[1]]
# ConDnect mask points to neighbors with -1's
index = (neighbors >= 0)
i = np.concatenate((i, grid[gridIdx[0][index], gridIdx[1][index]]))
j = np.concatenate((j, neighbors[index]))
s = np.concatenate((s, -np.ones(np.count_nonzero(index))))
D = sparse.coo_matrix((s, (i.astype(int), j.astype(int)))).tocsr()
sol = spsolve(D, rightSide)
I[maskIdx] = sol
return I
def formRightSide(I, maskPerimeter):
height, width = I.shape
perimeterValues = np.zeros((height, width))
perimeterValues[maskPerimeter] = I[maskPerimeter]
rightSide = np.zeros((height, width))
rightSide[1:height - 1, 1:width - 1] = (
perimeterValues[0:height - 2, 1:width - 1] +
perimeterValues[2:height, 1:width - 1] +
perimeterValues[1:height - 1, 0:width - 2] +
perimeterValues[1:height - 1, 2:width])
rightSide[1:height - 1, 0] = (
perimeterValues[0:height - 2, 0] + perimeterValues[2:height, 0] +
perimeterValues[1:height - 1, 1])
rightSide[1:height - 1, width - 1] = (
perimeterValues[0:height - 2, width - 1] +
perimeterValues[2:height, width - 1] +
perimeterValues[1:height - 1, width - 2])
rightSide[0, 1:width - 1] = (
perimeterValues[1, 1:width - 1] + perimeterValues[0, 0:width - 2] +
perimeterValues[0, 2:width])
rightSide[height - 1, 1:width - 1] = (
perimeterValues[height - 2, 1:width - 1] +
perimeterValues[height - 1, 0:width - 2] +
perimeterValues[height - 1, 2:width])
rightSide[0, 0] = perimeterValues[0, 1] + perimeterValues[1, 0]
rightSide[0, width - 1] = (
perimeterValues[0, width - 2] + perimeterValues[1, width - 1])
rightSide[height - 1, 0] = (
perimeterValues[height - 2, 0] + perimeterValues[height - 1, 1])
rightSide[height - 1, width - 1] = (perimeterValues[height - 2, width - 1] +
perimeterValues[height - 1, width - 2])
return rightSide
def computeNumberOfNeighbors(height, width):
# Initialize
numNeighbors = np.zeros((height, width))
# Interior pixels have 4 neighbors
numNeighbors[1:height - 1, 1:width - 1] = 4
# Border pixels have 3 neighbors
numNeighbors[1:height - 1, (0, width - 1)] = 3
numNeighbors[(0, height - 1), 1:width - 1] = 3
# Corner pixels have 2 neighbors
numNeighbors[(0, 0, height - 1, height - 1), (0, width - 1, 0,
width - 1)] = 2
return numNeighbors
def padMatrix(grid):
height, width = grid.shape
gridPadded = -np.ones((height + 2, width + 2))
gridPadded[1:height + 1, 1:width + 1] = grid
gridPadded = gridPadded.astype(grid.dtype)
return gridPadded
if __name__ == '__main__':
import time
x = np.linspace(0, 255, 500)
xv, _ = np.meshgrid(x, x)
image = ((xv + np.transpose(xv)) / 2.0).astype(int)
mask = np.zeros((500, 500))
mask[100:259, 100:259] = 1
mask = (mask > 0)
image[mask] = 0
st = time.time()
inpaint = regionfill(image, mask, 0.5).astype(np.uint8)
print(time.time() - st)
cv2.imshow('img', np.concatenate((image.astype(np.uint8), inpaint)))
cv2.waitKey()
|