parent
66e654b8e5
commit
067d1000f6
@ -1,57 +0,0 @@
|
||||
from matplotlib.widgets import RectangleSelector
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from inpaint import Inpaint
|
||||
|
||||
|
||||
def onselect(eclick, erelease):
|
||||
x1, y1 = eclick.xdata, eclick.ydata
|
||||
x2, y2 = erelease.xdata, erelease.ydata
|
||||
print("drawing")
|
||||
print(Demo.input)
|
||||
Demo.ax.imshow(Demo.input)
|
||||
plt.draw()
|
||||
output = Inpaint(Demo.input,Demo.mask,2)
|
||||
Demo.ax.imshow(output)
|
||||
plt.draw()
|
||||
print("drawed")
|
||||
|
||||
class Demo:
|
||||
ax = None
|
||||
input = None
|
||||
mask = None
|
||||
|
||||
@staticmethod
|
||||
def display(bimg):
|
||||
if Demo.ax == None:
|
||||
fig, Demo.ax = plt.subplots()
|
||||
Demo.ax.imshow(bimg)
|
||||
toggle_selector = RectangleSelector(Demo.ax, onselect, useblit=True,
|
||||
button=[1], minspanx=5, minspany=5, spancoords='pixels',
|
||||
interactive=True)
|
||||
plt.axis('off')
|
||||
plt.show()
|
||||
return
|
||||
if len(bimg.shape) != 3:
|
||||
return
|
||||
|
||||
fig, Demo.ax = plt.subplots()
|
||||
Demo.ax.imshow(bimg)
|
||||
plt.draw()
|
||||
plt.axis('off')
|
||||
plt.show()
|
||||
|
||||
@staticmethod
|
||||
def loadImage(filename):
|
||||
img = plt.imread(filename)
|
||||
if img.dtype == np.float32:
|
||||
img = (img * 255).astype(np.uint8)
|
||||
img = img[:,:,0:3]
|
||||
Demo.display(img)
|
||||
return img
|
||||
|
||||
@staticmethod
|
||||
def setValue(input,mask):
|
||||
Demo.input = input
|
||||
Demo.mask = mask
|
||||
|
@ -1,164 +1,142 @@
|
||||
from matplotlib.widgets import RectangleSelector
|
||||
import matplotlib.pyplot as plt
|
||||
from random import randint
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
def initialPatchMatch(img,x1,y1,x2,y2,patchSize=129):
|
||||
def getDist(pValue1, pValue2):
|
||||
return np.sum((pValue1 - pValue2) ** 2)
|
||||
from maskedImage import MaskedImage
|
||||
from nnf import Nnf
|
||||
|
||||
def initializePermimiter(finish=False):
|
||||
perimeter = []
|
||||
for x in range(x1, x2 + 1):
|
||||
perimeter.append((x, y1))
|
||||
perimeter.append((x, y2))
|
||||
if finish:
|
||||
perimeter.append((x,y1-1))
|
||||
perimeter.append((x,y2+1))
|
||||
|
||||
for y in range(y1 + 1, y2):
|
||||
perimeter.append((x1, y))
|
||||
perimeter.append((x2, y))
|
||||
if finish:
|
||||
perimeter.append((x1-1,y))
|
||||
perimeter.append((x2+1,y))
|
||||
return np.array(perimeter)
|
||||
def read(file):
|
||||
img = plt.imread(file)
|
||||
if img.dtype == np.float32:
|
||||
img = (img * 255).astype(np.uint8)
|
||||
img = img[:,:,0:3]
|
||||
return img
|
||||
|
||||
def getRandomPatchFromPerimiter(perimiter):
|
||||
x,y = perimiter[np.random.randint(len(perimiter))]
|
||||
patch = np.array([[i, j] for i in range(x - semiPatch, x + semiPatch + 1)
|
||||
for j in range(y - semiPatch, y + semiPatch + 1)])
|
||||
return patch
|
||||
def doTheInpainting(img,mask,radius):
|
||||
def maximizeForTheScale(scale):
|
||||
iterEM = 1+2*scale
|
||||
iterNnf = min(7,1+scale)
|
||||
source = sourceToTarget.input
|
||||
target = targetToSource.output
|
||||
newTarget = None
|
||||
for emloop in range(1,iterEM+1):
|
||||
if (newTarget != None):
|
||||
sourceToTarget.output = newTarget
|
||||
targetToSource.input = newTarget
|
||||
target = newTarget
|
||||
newTarget = None
|
||||
|
||||
for y in range(source.height):
|
||||
for x in range(source.width):
|
||||
if not source.containsMask(x,y,radius):
|
||||
sourceToTarget.field[y,x] = (x,y,0)
|
||||
for y in range(target.height):
|
||||
for x in range(target.width):
|
||||
if not source.containsMask(x,y,radius):
|
||||
targetToSource.field[y,x] = (x,y,0)
|
||||
sourceToTarget.minimize(iterNnf)
|
||||
targetToSource.minimize(iterNnf)
|
||||
|
||||
def getZoneMask(zoneValue,outside):
|
||||
mask = []
|
||||
for value in zoneValue:
|
||||
mask.append((value.sum() == 0) ^outside)
|
||||
return np.array(mask)
|
||||
|
||||
def applyMask(patch,mask,oposed=False):
|
||||
return patch[mask^oposed]
|
||||
upscaled = False
|
||||
if scale>=1 and emloop == iterEM:
|
||||
newSource = pyramid[scale-1]
|
||||
newTarget = target.upscale(newSource.height,newSource.width)
|
||||
upscaled = True
|
||||
else:
|
||||
newSource = pyramid[scale]
|
||||
newTarget = target.copy()
|
||||
upscaled = False
|
||||
|
||||
def getValueFromPatch(patch):
|
||||
ret = img[patch[0][1]:patch[0][1]+patchSize,patch[0][0]:patch[0][0]+patchSize]
|
||||
ret = ret.transpose(1, 0, 2)
|
||||
return ret.reshape(-1, 3)
|
||||
|
||||
def getRandomPatch(patchCoordFound):
|
||||
if (len(patchCoordFound) == 0):
|
||||
#TODO peut être trouver un patch autour du trou et verrifier que pas dans le trou
|
||||
x = randint(semiPatch,width-semiPatch-1)
|
||||
y = randint(semiPatch,height-semiPatch-1)
|
||||
patch = np.array([[i, j] for i in range(x - semiPatch, x + semiPatch + 1)
|
||||
for j in range(y - semiPatch, y + semiPatch + 1)])
|
||||
else:
|
||||
patch = patchCoordFound[randint(0,len(patchCoordFound)-1)]
|
||||
return patch
|
||||
vote = np.zeros((newTarget.width, newTarget.height, 4))
|
||||
ExpectationStep(sourceToTarget,True,vote,newSource,upscaled)
|
||||
ExpectationStep(targetToSource,False,vote,newSource,upscaled)
|
||||
MaximizationStep(newTarget, vote)
|
||||
result = cv2.resize(newTarget.image, (initial.width, initial.height), interpolation=cv2.INTER_AREA)
|
||||
plt.imshow(result)
|
||||
plt.pause(0.01)
|
||||
return newTarget, sourceToTarget, targetToSource
|
||||
|
||||
def getBestNeigbourPatch(zoneMask,filteredZoneValue,dist,patch,offset):
|
||||
voisin = [[-1,-1],[-1,0],[0,-1],[0,0],[1,-1],[-1,1],[0,1],[1,0],[1,1]]
|
||||
found = False
|
||||
bPatch = []
|
||||
for x,y in voisin:
|
||||
nPatch = patch.copy()
|
||||
nPatch[:,0] += x*offset
|
||||
nPatch[:,1] += y*offset
|
||||
if np.any(nPatch < 0) or np.any(nPatch[:,0] >= width) or np.any(nPatch[:,1] >= height):
|
||||
#TODO verrifier que le patch est pas dans le troue si non ff
|
||||
continue
|
||||
nPatchValue = getValueFromPatch(nPatch)
|
||||
filteredPatchValue = applyMask(nPatchValue,zoneMask)
|
||||
nDist = getDist(filteredZoneValue,filteredPatchValue)
|
||||
if (nDist < dist):
|
||||
dist = nDist
|
||||
bPatch = nPatch
|
||||
found = True
|
||||
return found,bPatch,dist
|
||||
initial = MaskedImage(img,mask)
|
||||
radius = radius
|
||||
pyramid = [initial]
|
||||
source = initial
|
||||
while source.width>radius and source.height>radius:
|
||||
source = source.downsample()
|
||||
pyramid.append(source)
|
||||
maxLevel = len(pyramid)
|
||||
|
||||
for level in range(maxLevel-1,0,-1):
|
||||
source = pyramid[level]
|
||||
if (level == maxLevel-1):
|
||||
target = source.copy()
|
||||
for y in range(target.height):
|
||||
for x in range(target.width):
|
||||
target.mask[y,x] = False
|
||||
sourceToTarget = Nnf(source,target,radius)
|
||||
sourceToTarget.randomize()
|
||||
|
||||
def getBestPatchForZone(zoneValue,zoneMask,patchCoordFound):
|
||||
filteredZoneValue = applyMask(zoneValue,zoneMask)
|
||||
patch = getRandomPatch(patchCoordFound)
|
||||
patchValue = getValueFromPatch(patch)
|
||||
filteredPatchValue = applyMask(patchValue,zoneMask)
|
||||
dist = getDist(filteredZoneValue,filteredPatchValue)
|
||||
offset = 1
|
||||
while offset < min(width,height):
|
||||
found, nPatch,nDist = getBestNeigbourPatch(zoneMask,filteredZoneValue,dist,patch,offset)
|
||||
if (found):
|
||||
patch = nPatch
|
||||
dist = nDist
|
||||
offset = 1
|
||||
else:
|
||||
offset*=2
|
||||
patchCoordFound.append(patch)
|
||||
return patchValue
|
||||
targetToSource = Nnf(target,source,radius)
|
||||
targetToSource.randomize()
|
||||
else:
|
||||
newNnf = Nnf(source,target,radius)
|
||||
newNnf.initializeFromNnf(sourceToTarget)
|
||||
sourceToTarget = newNnf
|
||||
|
||||
def applyPatch(filteredZone,zoneMask, patchValue):
|
||||
filteredPatchValue = applyMask(patchValue,zoneMask,True)
|
||||
for i in range(len(filteredZone)) :
|
||||
img[filteredZone[i][1],filteredZone[i][0]] = filteredPatchValue[i]
|
||||
|
||||
def updatePerimiter(filteredZone,perimiter):
|
||||
for x,y in filteredZone:
|
||||
if ((x,y) in filteredZone):
|
||||
perimiter = np.delete(perimiter, np.where((perimiter == [x, y]).all(axis=1))[0], axis=0)
|
||||
voisin = [[-1,-1],[-1,0],[0,-1],[0,0],[1,-1],[-1,1],[0,1],[1,0],[1,1]]
|
||||
for x,y in filteredZone:
|
||||
for offsetx,offsety in voisin:
|
||||
if img[y+offsety,x+offsetx].sum() == 0:
|
||||
perimiter = np.vstack((perimiter, [x+offsetx, y+offsety]))
|
||||
return perimiter
|
||||
newNnfRev = Nnf(target,source,radius)
|
||||
newNnfRev.initializeFromNnf(targetToSource)
|
||||
targetToSource = newNnfRev
|
||||
target, sourceToTarget, targetToSource = maximizeForTheScale(level)
|
||||
plt.imshow(target.image)
|
||||
plt.pause(0.01)
|
||||
return target.image
|
||||
|
||||
def addEdge(edges,zone):
|
||||
# pas des deux coté car zone pas filteredZone pour endroit biscornue
|
||||
x,y = zone[0]
|
||||
for xx in range(x,x+patchSize):
|
||||
if x1<=xx<=x2:
|
||||
if y1<=y<=y2:
|
||||
edges.append([xx,y])
|
||||
if y1<=y+patchSize<=y2:
|
||||
edges.append([xx,y+patchSize])
|
||||
for yy in range(y,y+patchSize):
|
||||
if y1<=yy<=y2:
|
||||
if x1<=x<=x2:
|
||||
edges.append([x,yy])
|
||||
if x1<=x+patchSize<=x2:
|
||||
edges.append([x+patchSize,yy])
|
||||
return edges
|
||||
def ExpectationStep(nnf,sourceToTarget, vote, source, upscale):
|
||||
for y in range(nnf.input.height):
|
||||
for x in range(nnf.input.width):
|
||||
xp, yp, dp = nnf.field[y,x]
|
||||
w = MaskedImage.similarity[dp]
|
||||
for dy in range(-nnf.patchSize,nnf.patchSize):
|
||||
for dx in range(-nnf.patchSize,nnf.patchSize):
|
||||
if sourceToTarget:
|
||||
xs = x+dx
|
||||
ys = y+dy
|
||||
xt = xp+dx
|
||||
yt = yp+dy
|
||||
else:
|
||||
xs = xp+dx
|
||||
ys = yp+dy
|
||||
xt = x+dx
|
||||
yt = y+dy
|
||||
if not 0<=xs<nnf.input.width:
|
||||
continue
|
||||
if not 0<=ys<nnf.input.height:
|
||||
continue
|
||||
if not 0<=xt<nnf.input.width:
|
||||
continue
|
||||
if not 0<=yt<nnf.input.height:
|
||||
continue
|
||||
if upscale:
|
||||
weightedCopy(source,2*xs,2*ys,vote,2*xt,2*yt,w)
|
||||
weightedCopy(source,2*xs+1,2*ys,vote,2*xt+1,2*yt,w)
|
||||
weightedCopy(source,2*xs,2*ys+1,vote,2*xt,2*yt+1,w)
|
||||
weightedCopy(source,2*xs+1,2*ys+1,vote,2*xt+1,2*yt+1,w)
|
||||
else:
|
||||
weightedCopy(source,xs,ys,vote,xt,yt,w)
|
||||
|
||||
def smoothEdges(edges):
|
||||
perimiter = initializePermimiter(True)
|
||||
edges.extend(perimiter.tolist())
|
||||
edges = np.array(edges)
|
||||
offsets = np.array([[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]])
|
||||
def weightedCopy(src,xs,ys,vote,xd,yd,w):
|
||||
if src.mask[ys,xs]:
|
||||
return
|
||||
vote[xd,yd,0] += w*src.image[ys,xs,0]
|
||||
vote[xd,yd,1] += w*src.image[ys,xs,1]
|
||||
vote[xd,yd,2] += w*src.image[ys,xs,2]
|
||||
vote[xd,yd,3] += w
|
||||
|
||||
for edge in edges:
|
||||
neighbors = edge + offsets[:,None]
|
||||
neighbors = neighbors.reshape(-1,2)
|
||||
valid_neighbors = neighbors[
|
||||
(neighbors[:,0] >= 0) & (neighbors[:,0] < width) &
|
||||
(neighbors[:,1] >= 0) & (neighbors[:,1] < height)
|
||||
]
|
||||
if len(valid_neighbors) > 0:
|
||||
neighbor_values = img[valid_neighbors[:,1], valid_neighbors[:,0]]
|
||||
avg_value = np.mean(neighbor_values, axis=0)
|
||||
img[edge[1], edge[0]] = avg_value
|
||||
|
||||
semiPatch = int(patchSize/2)
|
||||
height, width, _ = img.shape
|
||||
patchCoordFound = []
|
||||
edges = []
|
||||
|
||||
perimiter = initializePermimiter()
|
||||
while len(perimiter)> 0:
|
||||
zone = getRandomPatchFromPerimiter(perimiter)
|
||||
edges = addEdge(edges,zone)
|
||||
zoneValue = getValueFromPatch(zone)
|
||||
zoneMask = getZoneMask(zoneValue,True)
|
||||
filteredZoneInside = applyMask(zone,zoneMask,True)
|
||||
patchValue = getBestPatchForZone(zoneValue,zoneMask,patchCoordFound)
|
||||
applyPatch(filteredZoneInside,zoneMask,patchValue)
|
||||
perimiter = updatePerimiter(filteredZoneInside,perimiter)
|
||||
smoothEdges(edges)
|
||||
return img
|
||||
def MaximizationStep(target,vote):
|
||||
for y in range(target.height):
|
||||
for x in range(target.width):
|
||||
if vote[x,y,3]>0:
|
||||
r = int(vote[x,y,0]/vote[x,y,3])
|
||||
g = int(vote[x,y,1]/vote[x,y,3])
|
||||
b = int(vote[x,y,2]/vote[x,y,3])
|
||||
target.image[y,x] = (r,g,b)
|
||||
target.mask[y,x] = False
|
@ -1,143 +0,0 @@
|
||||
import numpy as np
|
||||
from maskedImage import MaskedImage
|
||||
from nnf import Nnf
|
||||
|
||||
class Inpaint:
|
||||
def __init__(self,input,mask,radius):
|
||||
self.initial = MaskedImage(input,mask)
|
||||
self.radius = radius
|
||||
self.pyramid = [self.initial]
|
||||
source = self.initial
|
||||
while source.width>radius and source.height>radius:
|
||||
source = source.downsample()
|
||||
self.pyramid.append(source)
|
||||
maxLevel = len(self.pyramid)
|
||||
|
||||
for level in range(maxLevel-1,0,-1):
|
||||
print(level)
|
||||
source = self.pyramid[level]
|
||||
if (level == maxLevel-1):
|
||||
target = source.copy()
|
||||
for y in range(target.height):
|
||||
for x in range(target.width):
|
||||
target.mask[y,x] = False
|
||||
self.nnfSourceToTarget = Nnf(source,target,radius)
|
||||
self.nnfSourceToTarget.randomize()
|
||||
|
||||
self.nnfTargetToSource = Nnf(target,source,radius)
|
||||
self.nnfTargetToSource.randomize()
|
||||
else:
|
||||
newNnf = Nnf(source,target,radius)
|
||||
newNnf.initializeFromNnf(self.nnfSourceToTarget)
|
||||
self.nnfSourceToTarget = newNnf
|
||||
|
||||
newNnfRev = Nnf(target,source,radius)
|
||||
newNnfRev.initializeFromNnf(self.nnfTargetToSource)
|
||||
self.nnfTargetToSource = newNnfRev
|
||||
target = self.ExpectationMaximization(level)
|
||||
return target.image
|
||||
|
||||
def ExpectationMaximization(self,level):
|
||||
iterEM = 1+2*level
|
||||
iterNnf = min(7,1+level)
|
||||
source = self.nnfSourceToTarget.input
|
||||
target = self.nnfTargetToSource.output
|
||||
newTarget = None
|
||||
for emloop in range(1,iterEM+1):
|
||||
if (newTarget != None):
|
||||
self.nnfSourceToTarget.output = newTarget
|
||||
self.nnfTargetToSource.input = newTarget
|
||||
target = newTarget
|
||||
newTarget = None
|
||||
|
||||
for y in range(source.height):
|
||||
for x in range(source.width):
|
||||
if not source.containsMask(x,y,self.radius):
|
||||
self.nnfSourceToTarget.field[y,x,0] = x
|
||||
self.nnfSourceToTarget.field[y,x,1] = y
|
||||
self.nnfSourceToTarget.field[y,x,2] = 0
|
||||
for y in range(target.height):
|
||||
for x in range(target.width):
|
||||
if not source.containsMask(x,y,self.radius):
|
||||
self.nnfTargetToSource.field[y,x,0] = x
|
||||
self.nnfTargetToSource.field[y,x,1] = y
|
||||
self.nnfTargetToSource.field[y,x,2] = 0
|
||||
self.nnfSourceToTarget.minimize(iterNnf)
|
||||
self.nnfTargetToSource.minimize(iterNnf)
|
||||
|
||||
upscaled = False
|
||||
if level>=1 and emloop == iterEM:
|
||||
newSource = self.pyramid[level-1]
|
||||
newTarget = target.upscale(newSource.height,newSource.width)
|
||||
upscaled = True
|
||||
else:
|
||||
newSource = self.pyramid[level]
|
||||
newTarget = target.copy()
|
||||
upscaled = False
|
||||
|
||||
vote = np.zeros((newTarget.width, newTarget.height, 4))
|
||||
self.ExpectationStep(self.nnfSourceToTarget,True,vote,newSource,upscaled)
|
||||
self.ExpectationStep(self.nnfTargetToSource,False,vote,newSource,upscaled)
|
||||
|
||||
self.MaximizationStep(newTarget, vote)
|
||||
result = MaskedImage.resize(newTarget.image,self.initial.width,self.initial.height)
|
||||
from demo import Demo
|
||||
Demo.display(result)
|
||||
return newTarget
|
||||
|
||||
def ExpectationStep(self,nnf,sourceToTarget, vote, source, upscale):
|
||||
for y in range(nnf.input.height):
|
||||
for x in range(nnf.input.width):
|
||||
xp = nnf.field[y,x,0]
|
||||
yp = nnf.field[y,x,1]
|
||||
dp = nnf.field[y,x,2]
|
||||
w = MaskedImage.similarity[dp]
|
||||
for dy in range(-nnf.patchSize,nnf.patchSize):
|
||||
for dx in range(-nnf.patchSize,nnf.patchSize):
|
||||
if sourceToTarget:
|
||||
xs = x+dx
|
||||
ys = y+dy
|
||||
xt = xp+dx
|
||||
yt = yp+dy
|
||||
else:
|
||||
xs = xp+dx
|
||||
ys = yp+dy
|
||||
xt = x+dx
|
||||
yt = y+dy
|
||||
if not 0<=xs<nnf.input.width:
|
||||
continue
|
||||
if not 0<=ys<nnf.input.height:
|
||||
continue
|
||||
if not 0<=xt<nnf.input.width:
|
||||
continue
|
||||
if not 0<=yt<nnf.input.height:
|
||||
continue
|
||||
if upscale:
|
||||
self.weightedCopy(source,2*xs,2*ys,vote,2*xt,2*yt,w)
|
||||
self.weightedCopy(source,2*xs+1,2*ys,vote,2*xt+1,2*yt,w)
|
||||
self.weightedCopy(source,2*xs,2*ys+1,vote,2*xt,2*yt+1,w)
|
||||
self.weightedCopy(source,2*xs+1,2*ys+1,vote,2*xt+1,2*yt+1,w)
|
||||
else:
|
||||
self.weightedCopy(source,xs,ys,vote,xt,yt,w)
|
||||
|
||||
def weightedCopy(self,src,xs,ys,vote,xd,yd,w):
|
||||
if src.mask[ys,xs]:
|
||||
return
|
||||
vote[xd,yd,0] += w*src.image[ys,xs,0]
|
||||
vote[xd,yd,1] += w*src.image[ys,xs,1]
|
||||
vote[xd,yd,2] += w*src.image[ys,xs,2]
|
||||
vote[xd,yd,3] += w
|
||||
|
||||
def MaximizationStep(self,target,vote):
|
||||
for y in range(target.height):
|
||||
for x in range(target.width):
|
||||
if vote[x,y,3]>0:
|
||||
r = int(vote[x,y,0]/vote[x,y,3])
|
||||
g = int(vote[x,y,1]/vote[x,y,3])
|
||||
b = int(vote[x,y,2]/vote[x,y,3])
|
||||
target.image[y,x,0] = r
|
||||
target.image[y,x,1] = g
|
||||
target.image[y,x,2] = b
|
||||
target.mask[y,x] = False
|
||||
|
||||
|
@ -1,83 +0,0 @@
|
||||
from matplotlib.widgets import RectangleSelector
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
def doKnn(img,x1,y1,x2,y2):
|
||||
|
||||
def getNotInBoundNeighbour(neighbour, x1,y1,x2,y2):
|
||||
mask = np.logical_or(
|
||||
np.logical_or(neighbour[:, 0] < y1, neighbour[:, 0] > y2),
|
||||
np.logical_or(neighbour[:, 1] < x1, neighbour[:, 1] > x2)
|
||||
)
|
||||
return neighbour[mask]
|
||||
|
||||
def neighbourReelPixel(x,y):
|
||||
tNeighbour = np.copy(neighbour)
|
||||
tNeighbour = tNeighbour + np.array([y,x])
|
||||
return tNeighbour
|
||||
|
||||
def getAvgPixelFromNeighbour(neighbour):
|
||||
return np.mean(img[neighbour[:,0],neighbour[:,1]], axis=0)
|
||||
|
||||
neighbour = np.array([[-1,-1],[-1,0],[0,-1],[-1,1],[1,-1],[0,1],[1,0],[1,1]])
|
||||
x1c = x1
|
||||
y1c = y1
|
||||
x2c = x2
|
||||
y2c = y2
|
||||
# tant que les pixels en périphérie du trou ne se rejoignent pas alors le trou n'est pas comblé
|
||||
while x1 != x2 and y1 != y2:
|
||||
# on comble les pixels à gauche et à droite
|
||||
for x in range(x1,x2):
|
||||
currentNeighbour1 = neighbourReelPixel(x,y1)
|
||||
currentNeighbour2 = neighbourReelPixel(x,y2)
|
||||
currentNeighbour1 = getNotInBoundNeighbour(currentNeighbour1,x1,y1,x2,y2)
|
||||
currentNeighbour2 = getNotInBoundNeighbour(currentNeighbour2,x1,y1,x2,y2)
|
||||
currentColor1 = getAvgPixelFromNeighbour(currentNeighbour1)
|
||||
currentColor2 = getAvgPixelFromNeighbour(currentNeighbour2)
|
||||
img[y1,x] = currentColor1
|
||||
img[y2,x] = currentColor2
|
||||
# puis en haut et en bas
|
||||
for y in range(y1,y2):
|
||||
currentNeighbour1 = neighbourReelPixel(x1,y)
|
||||
currentNeighbour2 = neighbourReelPixel(x2,y)
|
||||
currentNeighbour1 = getNotInBoundNeighbour(currentNeighbour1,x1,y1,x2,y2)
|
||||
currentNeighbour2 = getNotInBoundNeighbour(currentNeighbour2,x1,y1,x2,y2)
|
||||
currentColor1 = getAvgPixelFromNeighbour(currentNeighbour1)
|
||||
currentColor2 = getAvgPixelFromNeighbour(currentNeighbour2)
|
||||
img[y,x1] = currentColor1
|
||||
img[y,x2] = currentColor2
|
||||
x1 += 1
|
||||
x2 -= 1
|
||||
y1 += 1
|
||||
y2 -= 1
|
||||
|
||||
for x in range(x1c, x2c):
|
||||
for y in range(y1c, y2c):
|
||||
currentNeighbour = neighbourReelPixel(x, y)
|
||||
currentNeighbour = getNotInBoundNeighbour(currentNeighbour,0,0,0,0)
|
||||
currentColor = getAvgPixelFromNeighbour(currentNeighbour)
|
||||
img[y, x] = currentColor
|
||||
img[y1:y2,x1:x2]
|
||||
return img
|
||||
|
||||
img = plt.imread('asset/boat.png')
|
||||
|
||||
if len(img.shape) == 2:
|
||||
img = np.stack((img,)*3, axis=-1)
|
||||
|
||||
def onselect(eclick, erelease):
|
||||
x1, y1 = eclick.xdata, eclick.ydata
|
||||
x2, y2 = erelease.xdata, erelease.ydata
|
||||
|
||||
img_copy = np.copy(img)
|
||||
res = doKnn(img_copy,int(x1),int(y1),int(x2),int(y2))
|
||||
ax.imshow(res)
|
||||
plt.draw()
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.imshow(img)
|
||||
toggle_selector = RectangleSelector(ax, onselect, useblit=True,
|
||||
button=[1], minspanx=5, minspany=5, spancoords='pixels',
|
||||
interactive=True)
|
||||
plt.axis('off')
|
||||
plt.show()
|
@ -1,156 +0,0 @@
|
||||
from matplotlib.widgets import RectangleSelector
|
||||
import matplotlib.pyplot as plt
|
||||
from random import randint
|
||||
import numpy as np
|
||||
import cv2
|
||||
import time
|
||||
from function import *
|
||||
|
||||
def reScale(img,scale):
|
||||
height, width = img.shape[:2]
|
||||
new_height = int(height / scale)
|
||||
new_width = int(width / scale)
|
||||
scaled_img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_AREA)
|
||||
return scaled_img, new_height,new_width
|
||||
|
||||
def reScaleCoord(oWidth,oHeight,nWidth,nHeight,x1,y1,x2,y2):
|
||||
x1, x2 = int(x1*nWidth/oWidth),int(x2*nWidth/oWidth)
|
||||
y1, y2 = int(y1*nHeight/oHeight),int(y2*nHeight/oHeight)
|
||||
return x1,y1,x2,y2
|
||||
|
||||
def getDist(pValue1, pValue2):
|
||||
return np.sum((pValue1 - pValue2) ** 2)
|
||||
|
||||
def getRandomPatch(img2,pSize,x1,y1,x2,y2):
|
||||
height, width = img2.shape[:2]
|
||||
x = [randint(0,x1),randint(x2,width-pSize)][randint(0,1)]
|
||||
y = [randint(0,y1),randint(y2,height-pSize)][randint(0,1)]
|
||||
patch = getZoneFromCoord(x,y,pSize)
|
||||
return patch
|
||||
|
||||
def getValueFromPatch(img,patch,pSize):
|
||||
ret = img[patch[0][1]:patch[0][1]+pSize,patch[0][0]:patch[0][0]+pSize]
|
||||
ret = ret.transpose(1, 0, 2)
|
||||
return ret.reshape(-1, 3)
|
||||
|
||||
def applyPatch(img,zone,patchValue):
|
||||
for i in range(len(zone)) :
|
||||
img[zone[i][1],zone[i][0]] = patchValue[i]
|
||||
return img
|
||||
|
||||
def findBestPatchFromNeigbour(zoneValue,oDist,patch,offset,height,width,img,pSize):
|
||||
neigbour = [[-1,-1],[-1,0],[0,-1],[-1,1],[1,-1],[0,1],[1,0],[1,1]]
|
||||
trouve = False
|
||||
rP = patch
|
||||
for x,y in neigbour:
|
||||
p = patch.copy()
|
||||
p[:,0] += x*offset
|
||||
p[:,1] += y*offset
|
||||
if np.any(p < 0) or np.any(p[:,0] >= width) or np.any(p[:,1] >= height):
|
||||
continue
|
||||
value = getValueFromPatch(img,p,pSize)
|
||||
dist = getDist(zoneValue,value)
|
||||
if (dist < oDist):
|
||||
trouve = True
|
||||
oDist = dist
|
||||
rP = p
|
||||
return trouve, rP, oDist
|
||||
|
||||
def findBestPatch(img2,zone,zoneValue,pSize,pixSize,height,width,x1,y1,x2,y2):
|
||||
if not (x1<=zone[0][0]<=x2 and y1<=zone[0][1]):
|
||||
patch = zone.copy()
|
||||
return patch
|
||||
|
||||
patch = getRandomPatch(img2,int(pSize/pixSize)*2,x1,y1,x2,y2)
|
||||
pValue = getValueFromPatch(img2,patch,pSize)
|
||||
pdist = getDist(zoneValue,pValue)
|
||||
for i in range(500):
|
||||
tpatch = getRandomPatch(img2,int(pSize/pixSize)*2,x1,y1,x2,y2)
|
||||
tpValue = getValueFromPatch(img2,tpatch,pSize)
|
||||
tpdist = getDist(zoneValue,tpValue)
|
||||
if tpdist<pdist:
|
||||
pdist = tpdist
|
||||
patch = tpatch
|
||||
offset = 1
|
||||
while offset < min(height,width)/3:
|
||||
found, nPatch,nDist = findBestPatchFromNeigbour(zoneValue,pdist,patch,int(offset),height,width,img2,pSize)
|
||||
if found:
|
||||
patch = nPatch
|
||||
pdist = nDist
|
||||
offset = 1
|
||||
else:
|
||||
offset*=2
|
||||
return patch
|
||||
|
||||
def getZoneFromCoord(x,y,patchSize):
|
||||
zone = np.array([[i, j] for i in range(x, x + patchSize)
|
||||
for j in range(y, y + patchSize)])
|
||||
return zone
|
||||
|
||||
def rebuildImg(img1,img2,pixSize,x1,y1,x2,y2):
|
||||
height,width = img1.shape[:2]
|
||||
pSize = pixSize * 2
|
||||
for x in range(int(width/pSize)):
|
||||
for y in range(int(height/pSize)):
|
||||
zone = getZoneFromCoord(x*pSize,y*pSize,pSize)
|
||||
if not (x1<=x*pSize<=x2 and y1<=y*pSize<=y2):
|
||||
zoneValue = getValueFromPatch(img2,zone,pSize)
|
||||
applyPatch(img1,zone,zoneValue)
|
||||
continue
|
||||
zoneValue = getValueFromPatch(img1,zone,pSize)
|
||||
patch = findBestPatch(img2,zone,zoneValue,pSize,pixSize,height,width,x1,y1,x2,y2)
|
||||
patchValue = getValueFromPatch(img2,patch,pSize)
|
||||
img1 = applyPatch(img1,zone,patchValue)
|
||||
return img1
|
||||
|
||||
def doPatchMatch(image,x1,y1,x2,y2,scaleFactor=20,patchSize=129):
|
||||
oHeight, oWidth = image.shape[:2]
|
||||
rImage, nHeight, nWidth = reScale(image,scaleFactor)
|
||||
nx1, ny1, nx2, ny2 = reScaleCoord(oWidth,oHeight,nWidth,nHeight,x1,y1,x2,y2)
|
||||
rImage[ny1:ny2+1, nx1:nx2+1] = 0
|
||||
rImage = initialPatchMatch(rImage,nx1,ny1,nx2,ny2,5)
|
||||
|
||||
while scaleFactor != 2:
|
||||
scaleFactor -= 1
|
||||
rImage, nHeight, nWidth = reScale(rImage,scaleFactor/(scaleFactor+1))
|
||||
timg, h,w = reScale(image,scaleFactor)
|
||||
nx1, ny1, nx2, ny2 = reScaleCoord(oWidth,oHeight,w,h,x1,y1,x2,y2)
|
||||
rImage = rebuildImg(rImage,timg,int(h/nHeight),nx1,ny1,nx2,ny2)
|
||||
tempRes, _, _= reScale(rImage,1/scaleFactor)
|
||||
ax.imshow(tempRes)
|
||||
plt.draw()
|
||||
plt.pause(0.1)
|
||||
nHeight = h
|
||||
print(scaleFactor)
|
||||
|
||||
return tempRes
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
img = plt.imread('asset/vache.png')
|
||||
if img.dtype == np.float32:
|
||||
img = (img * 255).astype(np.uint8)
|
||||
img = img[:,:,0:3]
|
||||
|
||||
def onselect(eclick, erelease):
|
||||
x1, y1 = eclick.xdata, eclick.ydata
|
||||
x2, y2 = erelease.xdata, erelease.ydata
|
||||
|
||||
print("drawing")
|
||||
img_copy = np.copy(img)
|
||||
res = doPatchMatch(img_copy,int(x1),int(y1),int(x2),int(y2))
|
||||
|
||||
ax.imshow(res)
|
||||
plt.draw()
|
||||
print("drawed")
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.imshow(img)
|
||||
toggle_selector = RectangleSelector(ax, onselect, useblit=True,
|
||||
button=[1], minspanx=5, minspany=5, spancoords='pixels',
|
||||
interactive=True)
|
||||
|
||||
plt.axis('off')
|
||||
plt.show()
|
@ -0,0 +1,34 @@
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from function import *
|
||||
|
||||
plt.ion()
|
||||
plt.axis("off")
|
||||
|
||||
img = read("./dog/cow_img.bmp")
|
||||
maskImg = read("./dog/cow_mask.bmp")
|
||||
img = img.copy()
|
||||
|
||||
height, width = img.shape[:2]
|
||||
mask = np.zeros((height,width),dtype=bool)
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
mask[y,x] = maskImg[y,x] == 255
|
||||
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
if mask[y,x]:
|
||||
img[y,x] = (255,0,0)
|
||||
|
||||
plt.imshow(mask)
|
||||
plt.show()
|
||||
plt.title("mask de l'image")
|
||||
plt.pause(1)
|
||||
plt.title("génération de l'image")
|
||||
|
||||
img = doTheInpainting(img,mask,2)
|
||||
plt.imshow(img)
|
||||
plt.title("image final")
|
||||
plt.pause(20)
|
||||
|
||||
|
@ -1,213 +0,0 @@
|
||||
from matplotlib.widgets import RectangleSelector
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
|
||||
|
||||
def doPatchMatch(img,x1,y1,x2,y2,patchSize=17,nbRadomPatch=10):
|
||||
|
||||
def getPatchFromCoord(x,y):
|
||||
patch = np.array([[i, j] for i in range(patchSize) for j in range(patchSize)])
|
||||
patch[:,0] = patch[:,0] + x
|
||||
patch[:,1] = patch[:,1] + y
|
||||
return patch
|
||||
|
||||
def distance(patchValue1,patchValue2):
|
||||
mask = np.all(patchValue1 == [0, 0, 0], axis=-1)
|
||||
return np.sum((patchValue1[~mask] - patchValue2[~mask]) ** 2)
|
||||
|
||||
def getBestNeigbourPatch(xy,ogValue,ogDist,step):
|
||||
x, y = xy
|
||||
|
||||
dist = -1
|
||||
|
||||
xt, yt = x+step, y
|
||||
if (0 <= xt <= width - patchSize and 0 <= yt <= height - patchSize):
|
||||
patch = getPatchFromCoord(xt,yt)
|
||||
patchValue = patchToValue(patch)
|
||||
dist = distance(ogValue,patchValue)
|
||||
|
||||
xt, yt = x-step, y
|
||||
if (0 <= xt <= width - patchSize and 0 <= yt <= height - patchSize):
|
||||
tpatch = getPatchFromCoord(xt,yt)
|
||||
tpatchValue = patchToValue(tpatch)
|
||||
tdist = distance(ogValue,tpatchValue)
|
||||
if tdist < dist or dist == -1:
|
||||
dist = tdist
|
||||
patch = tpatch
|
||||
patchValue = tpatchValue
|
||||
|
||||
xt, yt = x, y+step
|
||||
if (0 <= xt <= width - patchSize and 0 <= yt <= height - patchSize):
|
||||
tpatch = getPatchFromCoord(xt,yt)
|
||||
tpatchValue = patchToValue(tpatch)
|
||||
tdist = distance(ogValue,tpatchValue)
|
||||
if tdist < dist or dist == -1:
|
||||
dist = tdist
|
||||
patch = tpatch
|
||||
patchValue = tpatchValue
|
||||
|
||||
xt, yt = x, y-step
|
||||
if (0 <= xt <= width - patchSize and 0 <= yt <= height - patchSize):
|
||||
tpatch = getPatchFromCoord(xt,yt)
|
||||
tpatchValue = patchToValue(tpatch)
|
||||
tdist = distance(ogValue,tpatchValue)
|
||||
if tdist < dist or dist == -1:
|
||||
dist = tdist
|
||||
patch = tpatch
|
||||
patchValue = tpatchValue
|
||||
if dist == -1:
|
||||
return False, None, None, None
|
||||
return dist < ogDist, patch, patchValue, dist
|
||||
|
||||
def getTheBestPatch(addr,ogValue):
|
||||
patchs = []
|
||||
patchsValue = []
|
||||
dists = []
|
||||
for i in range(nbRadomPatch):
|
||||
x,y = getRandomPatch()
|
||||
patch = getPatchFromCoord(x,y)
|
||||
patchValue = patchToValue(patch)
|
||||
dist = distance(ogValue,patchValue)
|
||||
patchs.append(patch)
|
||||
patchsValue.append(patchValue)
|
||||
dists.append(dist)
|
||||
|
||||
minIdx = np.argmin(np.array(dist))
|
||||
patch = patchs[minIdx]
|
||||
patchValue = patchsValue[minIdx]
|
||||
|
||||
ogDist = dists[minIdx]
|
||||
foundNew = True
|
||||
step = 5
|
||||
addr = addr[0]
|
||||
while foundNew:
|
||||
foundNew, tpatch, tpatchValue, tdist = getBestNeigbourPatch(addr,ogValue,ogDist,step)
|
||||
if (foundNew):
|
||||
addr = tpatch[patchSize//2]
|
||||
patch = tpatch
|
||||
patchValue = tpatchValue
|
||||
ogDist = tdist
|
||||
step = 5
|
||||
else:
|
||||
step = step*1.25
|
||||
foundNew = step < min(width, height)/2
|
||||
return patch, patchValue
|
||||
|
||||
|
||||
def patchToValue(patch):
|
||||
return img[patch[0][1]:patch[len(patch)-1][1], patch[0][0]:patch[len(patch)-1][0]]
|
||||
|
||||
def getRandomPatch():
|
||||
rx = np.random.randint(0, width - patchSize)
|
||||
ry = np.random.randint(0, height - patchSize)
|
||||
return rx, ry
|
||||
|
||||
def initializePermimiter():
|
||||
perimeter = []
|
||||
for x in range(x1, x2 + 1):
|
||||
perimeter.append((x, y1))
|
||||
perimeter.append((x, y2))
|
||||
|
||||
for y in range(y1 + 1, y2):
|
||||
perimeter.append((x1, y))
|
||||
perimeter.append((x2, y))
|
||||
img[y1:y2+1, x1:x2+1] = 0
|
||||
return np.array(perimeter)
|
||||
|
||||
def removeAndAddFromPerimiter(perimiter, addr):
|
||||
p= []
|
||||
npAddr = np.array(addr)
|
||||
for coord in perimiter:
|
||||
if not np.any(np.all(npAddr == np.array(coord), axis=1)):
|
||||
p.append(coord)
|
||||
|
||||
perimiter = p
|
||||
p1 = patchSize+2
|
||||
for dx in range(-1, p1):
|
||||
for dy in range(-1, p1):
|
||||
if (dx!=-1 and dx!=p1-1 and dy != -1 and dy != p1-1):
|
||||
continue
|
||||
nx, ny = addr[0,0] + dx, addr[0,1] + dy
|
||||
if 0 <= nx < width and 0 <= ny < height and img[ny, nx][0] == 0:
|
||||
if len(perimiter) == 0:
|
||||
perimiter.append([nx, ny])
|
||||
continue
|
||||
if not np.any(np.all(perimiter == np.array([int(nx), int(ny)]), axis=1)):
|
||||
perimiter.append([nx, ny])
|
||||
return perimiter
|
||||
|
||||
def applyPatch(patch,addr):
|
||||
value = patchToValue(addr)
|
||||
mask = np.all(value == [0, 0, 0], axis=-1)
|
||||
# regénérer addr en fonction du mask et des value
|
||||
patch = patch[~mask]
|
||||
for i in range(len(addr)):
|
||||
img[addr[i, 1], addr[i, 0]] = img[patch[i, 1],patch[i, 0]]
|
||||
|
||||
def getRandomFromPerimiter(perimiter):
|
||||
return perimiter[np.random.randint(len(perimiter))]
|
||||
|
||||
def loop(perimiter):
|
||||
x,y = getRandomFromPerimiter(perimiter)
|
||||
addr = getPatchFromCoord(x,y)
|
||||
ogValue = patchToValue(addr)
|
||||
patch,patchValue = getTheBestPatch(addr,ogValue)
|
||||
applyPatch(patch,addr)
|
||||
perimiter = removeAndAddFromPerimiter(perimiter,addr)
|
||||
return perimiter
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
semiPatch = int(patchSize/2)
|
||||
height, width, _ = img.shape
|
||||
|
||||
|
||||
|
||||
perimiter = initializePermimiter()
|
||||
it = 0
|
||||
|
||||
# perimiter = loop(perimiter)
|
||||
# perimiter = loop(perimiter)
|
||||
# perimiter = loop(perimiter)
|
||||
# for coord in perimiter:
|
||||
# img[coord[1], coord[0]] = [1,1,1,1]
|
||||
# img[img == -1] = 0
|
||||
|
||||
while len(perimiter)> 0:
|
||||
it += 1
|
||||
perimiter = loop(perimiter)
|
||||
if (it == 1000):
|
||||
it = 0
|
||||
print(len(perimiter))
|
||||
|
||||
return img
|
||||
|
||||
|
||||
|
||||
|
||||
img = plt.imread('asset/mur.jpg')
|
||||
|
||||
if len(img.shape) == 2:
|
||||
img = np.stack((img,)*3, axis=-1)
|
||||
|
||||
def onselect(eclick, erelease):
|
||||
x1, y1 = eclick.xdata, eclick.ydata
|
||||
x2, y2 = erelease.xdata, erelease.ydata
|
||||
|
||||
print("drawing")
|
||||
img_copy = np.copy(img)
|
||||
res = doPatchMatch(img_copy,int(x1),int(y1),int(x2),int(y2),33)
|
||||
ax.imshow(res)
|
||||
plt.draw()
|
||||
print("drawed")
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.imshow(img)
|
||||
toggle_selector = RectangleSelector(ax, onselect, useblit=True,
|
||||
button=[1], minspanx=5, minspany=5, spancoords='pixels',
|
||||
interactive=True)
|
||||
plt.axis('off')
|
||||
plt.show()
|
@ -1,166 +0,0 @@
|
||||
from matplotlib.widgets import RectangleSelector
|
||||
import matplotlib.pyplot as plt
|
||||
from random import randint
|
||||
import numpy as np
|
||||
|
||||
|
||||
def doPatchMatch(img,x1,y1,x2,y2,patchSize=65):
|
||||
def getDist(pValue1, pValue2):
|
||||
return np.sum((pValue1 - pValue2) ** 2)
|
||||
|
||||
def initializePermimiter():
|
||||
perimeter = []
|
||||
for x in range(x1, x2 + 1):
|
||||
perimeter.append((x, y1))
|
||||
perimeter.append((x, y2))
|
||||
|
||||
for y in range(y1 + 1, y2):
|
||||
perimeter.append((x1, y))
|
||||
perimeter.append((x2, y))
|
||||
img[y1:y2+1, x1:x2+1] = 0
|
||||
return np.array(perimeter)
|
||||
|
||||
def getRandomPatchFromPerimiter(perimiter):
|
||||
x,y = perimiter[np.random.randint(len(perimiter))]
|
||||
patch = np.array([[i, j] for i in range(x - semiPatch, x + semiPatch + 1)
|
||||
for j in range(y - semiPatch, y + semiPatch + 1)])
|
||||
return patch
|
||||
|
||||
def getZoneMask(zoneValue,outside):
|
||||
mask = []
|
||||
for value in zoneValue:
|
||||
mask.append((value.sum() == 0) ^outside)
|
||||
return np.array(mask)
|
||||
|
||||
def applyMask(patch,mask,oposed=False):
|
||||
patchf = []
|
||||
for i in range(len(mask)):
|
||||
if(mask[i]^oposed):
|
||||
patchf.append(patch[i])
|
||||
return np.array(patchf)
|
||||
|
||||
def getValueFromPatch(patch):
|
||||
value = []
|
||||
for x,y in patch:
|
||||
value.append(img[y,x])
|
||||
return np.array(value)
|
||||
|
||||
def getRandomPatch(patchCoordFound):
|
||||
if (len(patchCoordFound) ==0):
|
||||
#TODO peut être trouver un patch autour du trou et verrifier que pas dans le trou
|
||||
x = randint(semiPatch,width-semiPatch-1)
|
||||
y = randint(semiPatch,height-semiPatch-1)
|
||||
patch = np.array([[i, j] for i in range(x - semiPatch, x + semiPatch + 1)
|
||||
for j in range(y - semiPatch, y + semiPatch + 1)])
|
||||
else:
|
||||
patch = patchCoordFound[randint(0,len(patchCoordFound)-1)]
|
||||
return patch
|
||||
|
||||
def getBestNeigbourPatch(zoneMask,filteredZoneValue,dist,patch,offset):
|
||||
voisin = [[-1,-1],[-1,0],[0,-1],[0,0],[1,-1],[-1,1],[0,1],[1,0],[1,1]]
|
||||
found = False
|
||||
bPatch = []
|
||||
for x,y in voisin:
|
||||
nPatch = patch.copy()
|
||||
nPatch[:,0] += x*offset
|
||||
nPatch[:,1] += y*offset
|
||||
if np.any(nPatch < 0) or np.any(nPatch[:,0] >= width) or np.any(nPatch[:,1] >= height):
|
||||
#TODO verrifier que le patch est pas dans le troue si non ff
|
||||
continue
|
||||
nPatchValue = getValueFromPatch(nPatch)
|
||||
filteredPatchValue = applyMask(nPatchValue,zoneMask)
|
||||
nDist = getDist(filteredZoneValue,filteredPatchValue)
|
||||
if (nDist < dist):
|
||||
dist = nDist
|
||||
bPatch = nPatch
|
||||
found = True
|
||||
return found,bPatch,dist
|
||||
|
||||
|
||||
def getBestPatchForZone(zoneValue,zoneMask,patchCoordFound):
|
||||
filteredZoneValue = applyMask(zoneValue,zoneMask)
|
||||
patch = getRandomPatch(patchCoordFound)
|
||||
patchValue = getValueFromPatch(patch)
|
||||
filteredPatchValue = applyMask(patchValue,zoneMask)
|
||||
dist = getDist(filteredZoneValue,filteredPatchValue)
|
||||
offset = 1
|
||||
while offset < min(width,height)/3:
|
||||
found, nPatch,nDist = getBestNeigbourPatch(zoneMask,filteredZoneValue,dist,patch,offset)
|
||||
if (found):
|
||||
patch = nPatch
|
||||
dist = nDist
|
||||
offset = 1
|
||||
else:
|
||||
offset*=2
|
||||
patchCoordFound.append(patch)
|
||||
return patchValue
|
||||
|
||||
def applyPatch(zoneCoord,zoneMask, patchValue):
|
||||
filteredPatchValue = applyMask(patchValue,zoneMask,True)
|
||||
filteredZone = applyMask(zoneCoord,zoneMask,True)
|
||||
for i in range(len(filteredZone)) :
|
||||
img[filteredZone[i][1],filteredZone[i][0]] = filteredPatchValue[i]
|
||||
|
||||
def updatePerimiter(zone,zoneMask,perimiter):
|
||||
filteredZone = applyMask(zone,zoneMask,True)
|
||||
for x,y in filteredZone:
|
||||
if ((x,y) in filteredZone):
|
||||
perimiter = np.delete(perimiter, np.where((perimiter == [x, y]).all(axis=1))[0], axis=0)
|
||||
voisin = [[-1,-1],[-1,0],[0,-1],[0,0],[1,-1],[-1,1],[0,1],[1,0],[1,1]]
|
||||
for x,y in filteredZone:
|
||||
for offsetx,offsety in voisin:
|
||||
if img[y+offsety,x+offsetx].sum() == 0:
|
||||
perimiter = np.vstack((perimiter, [x+offsetx, y+offsety]))
|
||||
return perimiter
|
||||
|
||||
semiPatch = int(patchSize/2)
|
||||
height, width, _ = img.shape
|
||||
patchCoordFound = []
|
||||
eadges = []
|
||||
|
||||
perimiter = initializePermimiter()
|
||||
it = 0
|
||||
while len(perimiter)> 0:
|
||||
zone = getRandomPatchFromPerimiter(perimiter)
|
||||
zoneValue = getValueFromPatch(zone)
|
||||
zoneMask = getZoneMask(zoneValue,True)
|
||||
patchValue = getBestPatchForZone(zoneValue,zoneMask,patchCoordFound)
|
||||
applyPatch(zone,zoneMask,patchValue)
|
||||
perimiter = updatePerimiter(zone,zoneMask,perimiter)
|
||||
it +=1
|
||||
print(it)
|
||||
|
||||
return img
|
||||
|
||||
|
||||
|
||||
|
||||
# for x, y in zone:
|
||||
# if 0 <= x < width and 0 <= y < height:
|
||||
# img[y, x] = [255, 255, 255]
|
||||
# return img
|
||||
|
||||
img = plt.imread('asset/mur.jpg')
|
||||
if img.dtype == np.float32:
|
||||
img = (img * 255).astype(np.uint8)
|
||||
img = img[:,:,0:3]
|
||||
|
||||
|
||||
def onselect(eclick, erelease):
|
||||
x1, y1 = eclick.xdata, eclick.ydata
|
||||
x2, y2 = erelease.xdata, erelease.ydata
|
||||
|
||||
print("drawing")
|
||||
img_copy = np.copy(img)
|
||||
res = doPatchMatch(img_copy,int(x1),int(y1),int(x2),int(y2))
|
||||
ax.imshow(res)
|
||||
plt.draw()
|
||||
print("drawed")
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.imshow(img)
|
||||
toggle_selector = RectangleSelector(ax, onselect, useblit=True,
|
||||
button=[1], minspanx=5, minspany=5, spancoords='pixels',
|
||||
interactive=True)
|
||||
plt.axis('off')
|
||||
plt.show()
|
@ -1,26 +0,0 @@
|
||||
from demo import Demo
|
||||
import numpy as np
|
||||
from inpaint import Inpaint
|
||||
|
||||
inpute = Demo.loadImage("./dog/cow_img.bmp")
|
||||
maskImage = Demo.loadImage("./dog/cow_mask.bmp")
|
||||
inpute = np.copy(inpute)
|
||||
|
||||
height, width = inpute.shape[:2]
|
||||
mask = np.zeros((height,width),dtype=bool)
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
mask[y,x] = maskImage[y,x] == 255
|
||||
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
if mask[y,x]:
|
||||
inpute[y,x,0] = 255
|
||||
inpute[y,x,1] = 0
|
||||
inpute[y,x,2] = 0
|
||||
|
||||
Demo.setValue(inpute,mask)
|
||||
Demo.display(Demo.input)
|
||||
|
||||
output = Inpaint(Demo.input,Demo.mask,2)
|
||||
Demo.display(output)
|
@ -1,196 +0,0 @@
|
||||
from matplotlib.widgets import RectangleSelector
|
||||
import matplotlib.pyplot as plt
|
||||
from random import randint
|
||||
import numpy as np
|
||||
|
||||
def doPatchMatch(img,x1,y1,x2,y2,patchSize=129):
|
||||
def getDist(pValue1, pValue2):
|
||||
return np.sum((pValue1 - pValue2) ** 2)
|
||||
|
||||
def initializePermimiter(finish=False):
|
||||
perimeter = []
|
||||
for x in range(x1, x2 + 1):
|
||||
perimeter.append((x, y1))
|
||||
perimeter.append((x, y2))
|
||||
if finish:
|
||||
perimeter.append((x,y1-1))
|
||||
perimeter.append((x,y2+1))
|
||||
|
||||
for y in range(y1 + 1, y2):
|
||||
perimeter.append((x1, y))
|
||||
perimeter.append((x2, y))
|
||||
if finish:
|
||||
perimeter.append((x1-1,y))
|
||||
perimeter.append((x2+1,y))
|
||||
return np.array(perimeter)
|
||||
|
||||
def getRandomPatchFromPerimiter(perimiter):
|
||||
x,y = perimiter[np.random.randint(len(perimiter))]
|
||||
patch = np.array([[i, j] for i in range(x - semiPatch, x + semiPatch + 1)
|
||||
for j in range(y - semiPatch, y + semiPatch + 1)])
|
||||
return patch
|
||||
|
||||
def getZoneMask(zoneValue,outside):
|
||||
mask = []
|
||||
for value in zoneValue:
|
||||
mask.append((value.sum() == 0) ^outside)
|
||||
return np.array(mask)
|
||||
|
||||
def applyMask(patch,mask,oposed=False):
|
||||
return patch[mask^oposed]
|
||||
|
||||
def getValueFromPatch(patch):
|
||||
ret = img[patch[0][1]:patch[0][1]+patchSize,patch[0][0]:patch[0][0]+patchSize]
|
||||
ret = ret.transpose(1, 0, 2)
|
||||
return ret.reshape(-1, 3)
|
||||
|
||||
def getRandomPatch(patchCoordFound):
|
||||
if (len(patchCoordFound) == 0):
|
||||
#TODO peut être trouver un patch autour du trou et verrifier que pas dans le trou
|
||||
x = randint(semiPatch,width-semiPatch-1)
|
||||
y = randint(semiPatch,height-semiPatch-1)
|
||||
patch = np.array([[i, j] for i in range(x - semiPatch, x + semiPatch + 1)
|
||||
for j in range(y - semiPatch, y + semiPatch + 1)])
|
||||
else:
|
||||
patch = patchCoordFound[randint(0,len(patchCoordFound)-1)]
|
||||
return patch
|
||||
|
||||
def getBestNeigbourPatch(zoneMask,filteredZoneValue,dist,patch,offset):
|
||||
voisin = [[-1,-1],[-1,0],[0,-1],[0,0],[1,-1],[-1,1],[0,1],[1,0],[1,1]]
|
||||
found = False
|
||||
bPatch = []
|
||||
for x,y in voisin:
|
||||
nPatch = patch.copy()
|
||||
nPatch[:,0] += x*offset
|
||||
nPatch[:,1] += y*offset
|
||||
if np.any(nPatch < 0) or np.any(nPatch[:,0] >= width) or np.any(nPatch[:,1] >= height):
|
||||
#TODO verrifier que le patch est pas dans le troue si non ff
|
||||
continue
|
||||
nPatchValue = getValueFromPatch(nPatch)
|
||||
filteredPatchValue = applyMask(nPatchValue,zoneMask)
|
||||
nDist = getDist(filteredZoneValue,filteredPatchValue)
|
||||
if (nDist < dist):
|
||||
dist = nDist
|
||||
bPatch = nPatch
|
||||
found = True
|
||||
return found,bPatch,dist
|
||||
|
||||
|
||||
def getBestPatchForZone(zoneValue,zoneMask,patchCoordFound):
|
||||
filteredZoneValue = applyMask(zoneValue,zoneMask)
|
||||
patch = getRandomPatch(patchCoordFound)
|
||||
patchValue = getValueFromPatch(patch)
|
||||
filteredPatchValue = applyMask(patchValue,zoneMask)
|
||||
dist = getDist(filteredZoneValue,filteredPatchValue)
|
||||
offset = 1
|
||||
while offset < min(width,height)/2:
|
||||
found, nPatch,nDist = getBestNeigbourPatch(zoneMask,filteredZoneValue,dist,patch,offset)
|
||||
if (found):
|
||||
patch = nPatch
|
||||
dist = nDist
|
||||
offset = 1
|
||||
else:
|
||||
offset*=2
|
||||
patchCoordFound.append(patch)
|
||||
return patchValue
|
||||
|
||||
def applyPatch(filteredZone,zoneMask, patchValue):
|
||||
filteredPatchValue = applyMask(patchValue,zoneMask,True)
|
||||
for i in range(len(filteredZone)) :
|
||||
img[filteredZone[i][1],filteredZone[i][0]] = filteredPatchValue[i]
|
||||
|
||||
def updatePerimiter(filteredZone,perimiter):
|
||||
for x,y in filteredZone:
|
||||
if ((x,y) in filteredZone):
|
||||
perimiter = np.delete(perimiter, np.where((perimiter == [x, y]).all(axis=1))[0], axis=0)
|
||||
voisin = [[-1,-1],[-1,0],[0,-1],[0,0],[1,-1],[-1,1],[0,1],[1,0],[1,1]]
|
||||
for x,y in filteredZone:
|
||||
for offsetx,offsety in voisin:
|
||||
if img[y+offsety,x+offsetx].sum() == 0:
|
||||
perimiter = np.vstack((perimiter, [x+offsetx, y+offsety]))
|
||||
return perimiter
|
||||
|
||||
def addEdge(edges,zone):
|
||||
# pas des deux coté car zone pas filteredZone pour endroit biscornue
|
||||
x,y = zone[0]
|
||||
for xx in range(x,x+patchSize):
|
||||
if x1<=xx<=x2:
|
||||
if y1<=y<=y2:
|
||||
edges.append([xx,y])
|
||||
if y1<=y+patchSize<=y2:
|
||||
edges.append([xx,y+patchSize])
|
||||
for yy in range(y,y+patchSize):
|
||||
if y1<=yy<=y2:
|
||||
if x1<=x<=x2:
|
||||
edges.append([x,yy])
|
||||
if x1<=x+patchSize<=x2:
|
||||
edges.append([x+patchSize,yy])
|
||||
return edges
|
||||
|
||||
def smoothEdges(edges):
|
||||
perimiter = initializePermimiter(True)
|
||||
edges.extend(perimiter.tolist())
|
||||
edges = np.array(edges)
|
||||
offsets = np.array([[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]])
|
||||
|
||||
for edge in edges:
|
||||
neighbors = edge + offsets[:,None]
|
||||
neighbors = neighbors.reshape(-1,2)
|
||||
valid_neighbors = neighbors[
|
||||
(neighbors[:,0] >= 0) & (neighbors[:,0] < width) &
|
||||
(neighbors[:,1] >= 0) & (neighbors[:,1] < height)
|
||||
]
|
||||
if len(valid_neighbors) > 0:
|
||||
neighbor_values = img[valid_neighbors[:,1], valid_neighbors[:,0]]
|
||||
avg_value = np.mean(neighbor_values, axis=0)
|
||||
img[edge[1], edge[0]] = avg_value
|
||||
# for x,y in edges:
|
||||
# img[y,x] = [255,0,0]
|
||||
|
||||
semiPatch = int(patchSize/2)
|
||||
height, width, _ = img.shape
|
||||
patchCoordFound = []
|
||||
edges = []
|
||||
|
||||
perimiter = initializePermimiter()
|
||||
img[y1:y2+1, x1:x2+1] = 0
|
||||
it = 0
|
||||
while len(perimiter)> 0:
|
||||
zone = getRandomPatchFromPerimiter(perimiter)
|
||||
edges = addEdge(edges,zone)
|
||||
zoneValue = getValueFromPatch(zone)
|
||||
zoneMask = getZoneMask(zoneValue,True)
|
||||
filteredZoneInside = applyMask(zone,zoneMask,True)
|
||||
patchValue = getBestPatchForZone(zoneValue,zoneMask,patchCoordFound)
|
||||
applyPatch(filteredZoneInside,zoneMask,patchValue)
|
||||
perimiter = updatePerimiter(filteredZoneInside,perimiter)
|
||||
it +=1
|
||||
print(it)
|
||||
print("smoothing edges")
|
||||
smoothEdges(edges)
|
||||
return img
|
||||
|
||||
img = plt.imread('asset/vache.png')
|
||||
if img.dtype == np.float32:
|
||||
img = (img * 255).astype(np.uint8)
|
||||
img = img[:,:,0:3]
|
||||
|
||||
|
||||
def onselect(eclick, erelease):
|
||||
x1, y1 = eclick.xdata, eclick.ydata
|
||||
x2, y2 = erelease.xdata, erelease.ydata
|
||||
|
||||
print("drawing")
|
||||
img_copy = np.copy(img)
|
||||
res = doPatchMatch(img_copy,int(x1),int(y1),int(x2),int(y2))
|
||||
ax.imshow(res)
|
||||
plt.draw()
|
||||
print("drawed")
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.imshow(img)
|
||||
toggle_selector = RectangleSelector(ax, onselect, useblit=True,
|
||||
button=[1], minspanx=5, minspany=5, spancoords='pixels',
|
||||
interactive=True)
|
||||
plt.axis('off')
|
||||
plt.show()
|
Loading…
Reference in new issue