diff --git a/.gitignore b/.gitignore index ef069bc..0307e02 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ __pycache__/ *.so dog/ +old/ # Distribution / packaging .Python diff --git a/demo.py b/demo.py deleted file mode 100644 index b800be5..0000000 --- a/demo.py +++ /dev/null @@ -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 - diff --git a/function.py b/function.py index cc85936..38c8ad5 100644 --- a/function.py +++ b/function.py @@ -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= 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 \ No newline at end of file diff --git a/inpaint.py b/inpaint.py deleted file mode 100644 index 693111b..0000000 --- a/inpaint.py +++ /dev/null @@ -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<=xs0: - 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 - - \ No newline at end of file diff --git a/knn.py b/knn.py deleted file mode 100644 index d5813fa..0000000 --- a/knn.py +++ /dev/null @@ -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() diff --git a/maskedImage.py b/maskedImage.py index 3446963..becc1cc 100644 --- a/maskedImage.py +++ b/maskedImage.py @@ -1,5 +1,4 @@ import numpy as np -import cv2 class MaskedImage: DSCALE = 65535 @@ -28,39 +27,6 @@ class MaskedImage: return True return False - @staticmethod - def distance(source, xs, ys, target, xt, yt, patchSize): - ssd_max = 9 * 255 * 255 - distance, wsum = 0, 0 - - for dy in range(-patchSize, patchSize): - for dx in range(-patchSize, patchSize): - wsum += ssd_max - xks, yks = xs + dx, ys + dy - xkt, ykt = xt + dx, yt + dy - - if not (1 <= xks < source.width - 1 and 1 <= yks < source.height - 1): - distance += ssd_max - continue - if source.containsMask(xks, yks,patchSize): - distance += ssd_max - continue - if not (1 <= xkt < target.width - 1 and 1 <= ykt < target.height - 1): - distance += ssd_max - continue - if target.containsMask(xkt, ykt,patchSize): - distance += ssd_max - continue - - ssd = np.sum((source.image[yks, xks] - target.image[ykt, xkt]) ** 2) - distance += ssd - - return int(MaskedImage.DSCALE * distance / wsum) - - @staticmethod - def resize(image, newWidth, newHeight): - return cv2.resize(image, (newWidth, newHeight), interpolation=cv2.INTER_AREA) - def copy(self): return MaskedImage(image=self.image.copy(), mask=self.mask.copy()) @@ -115,5 +81,4 @@ class MaskedImage: newImage.mask[y,x] = False else: newImage.mask[y,x] = True - return newImage - + return newImage \ No newline at end of file diff --git a/multiScale.py b/multiScale.py deleted file mode 100644 index e3423d5..0000000 --- a/multiScale.py +++ /dev/null @@ -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 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() diff --git a/patchMatch2.py b/patchMatch2.py deleted file mode 100644 index 10968fb..0000000 --- a/patchMatch2.py +++ /dev/null @@ -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() diff --git a/script.py b/script.py deleted file mode 100644 index f01a5f3..0000000 --- a/script.py +++ /dev/null @@ -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) \ No newline at end of file diff --git a/smothPatch.py b/smothPatch.py deleted file mode 100644 index b3410fb..0000000 --- a/smothPatch.py +++ /dev/null @@ -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()