From 067d1000f6997954ec3a081cc8590160f10643c4 Mon Sep 17 00:00:00 2001 From: Ludovic CASTIGLIA Date: Wed, 5 Feb 2025 02:02:28 +0100 Subject: [PATCH] nouvel algo multi tout (patch,size,pass) --- .gitignore | 1 + demo.py | 57 ---------- function.py | 278 +++++++++++++++++++++++-------------------------- inpaint.py | 143 ------------------------- knn.py | 83 --------------- maskedImage.py | 37 +------ multiScale.py | 156 --------------------------- multiTout.py | 34 ++++++ nnf.py | 41 ++++++-- patchMatch.py | 213 ------------------------------------- patchMatch2.py | 166 ----------------------------- script.py | 26 ----- smothPatch.py | 196 ---------------------------------- 13 files changed, 194 insertions(+), 1237 deletions(-) delete mode 100644 demo.py delete mode 100644 inpaint.py delete mode 100644 knn.py delete mode 100644 multiScale.py create mode 100644 multiTout.py delete mode 100644 patchMatch.py delete mode 100644 patchMatch2.py delete mode 100644 script.py delete mode 100644 smothPatch.py 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()