diff --git a/app.py b/app.py new file mode 100644 index 0000000..e5616e0 --- /dev/null +++ b/app.py @@ -0,0 +1,79 @@ +from matplotlib.widgets import RectangleSelector +import matplotlib.pyplot as plt +import numpy as np + + + + +def patch_match(img, patch_size=3, iterations=1): + height, width, _ = img.shape + offsets = np.zeros((height, width, 2), dtype=np.int32) + + def random_offsets(): + return np.random.randint(-patch_size, patch_size + 1, size=(height, width, 2)) + + def distance(patch1, patch2): + return np.sum((patch1 - patch2) ** 2) + + def get_patch(x, y): + return img[max(0, y):min(height, max(0, y) + patch_size), max(0, x):min(width, max(0, x) + patch_size)] + + offsets = random_offsets() + + for _ in range(iterations): + for y in range(patch_size,height-patch_size*2): + for x in range(patch_size,width-patch_size*2): + best_offset = offsets[y, x] + best_distance = distance(get_patch(x, y), get_patch(x + best_offset[0], y + best_offset[1])) + for dy in range(-1, 2): + for dx in range(-1, 2): + if dx == 0 and dy == 0: + continue + new_offset = best_offset + [dx, dy] + if (new_offset[0]+x>width-patch_size or new_offset[1]+y>height-patch_size): + continue + new_distance = distance(get_patch(x, y), get_patch(x + new_offset[0], y + new_offset[1])) + if new_distance < best_distance: + best_distance = new_distance + best_offset = new_offset + offsets[y, x] = best_offset + + result = np.zeros_like(img) + for y in range(height): + for x in range(width): + offset = offsets[y, x] + result[y, x] = img[(y + offset[1]) % height, (x + offset[0]) % width] + + return result + + + + + +# Load the image using matplotlib +img = plt.imread('/home/UCA/lucastigli/patchMatch/boat.png') + + +def onselect(eclick, erelease): + x1, y1 = eclick.xdata, eclick.ydata + x2 = x1 + 150 + x2, y2 = erelease.xdata, erelease.ydata + + avg_color = np.mean(img, axis=(0, 1)) + + img_copy = np.copy(img) + img_copy[int(y1):int(y2), int(x1):int(x2)] = avg_color + res = patch_match(img_copy) + ax.imshow(res) + plt.draw() + print("drawed") + #ax.imshow(img_copy) + #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/app2.py b/app2.py new file mode 100644 index 0000000..be90632 --- /dev/null +++ b/app2.py @@ -0,0 +1,97 @@ +from matplotlib.widgets import RectangleSelector +import matplotlib.pyplot as plt +import numpy as np + + +def patchMatch(img,x1,y1,x2,y2,patchSize=20, iterations=1000): + height, width, _ = img.shape + img_copy = np.copy(img) + xx1 = max(0, x1-patchSize) + yy1 = max(0, y1-patchSize) + xx2 = min(width, x2+patchSize) + yy2 = min(height, y2+patchSize) + + if (xx2-xx1 < patchSize or yy2-yy1 < patchSize): + return img + + def getRandomPatch(): + rx = np.random.randint(0, width - patchSize) + ry = np.random.randint(0, height - patchSize) + return rx, ry + + def fusion(patch1, patch2): + return (patch1*2+patch2) / 3 + + def distance(patch1, patch2): + return np.sum((patch1 - patch2) ** 2) + + def gradientDescent(x, y, bestPatch, bestDistance): + neighbors = [(-1,0), (1,0), (0,-1), (0,1), (-1,-1), (-1,1), (1,-1), (1,1)] + patch = img[y:y + patchSize, x:x + patchSize] + hasChanged = True + while hasChanged: + hasChanged = False + for nx, ny in neighbors: + cx = bestPatch[0] + nx + cy = bestPatch[1] + ny + if cx < 0 or cy < 0 or cx >= width - patchSize or cy >= height - patchSize: + continue + + neighborPatch = img[cy:cy + patchSize, cx:cx + patchSize] + neighborDist = distance(patch, neighborPatch) + if neighborDist < bestDistance: + hasChanged = True + bestPatch = [cx, cy] + bestDistance = neighborDist + return bestPatch, bestDistance + + + for x in range(xx1,xx2-patchSize,int(patchSize/10)): + for y in range(yy1,yy2-patchSize,int(patchSize/10)): + px, py = getRandomPatch() + bestPatch = [px, py] + bestDistance = distance(img[y:y+patchSize,x:x+patchSize], img[py:py+patchSize,px:px+patchSize]) + firstDistance = np.copy(bestDistance) + for _ in range(iterations): + px, py = getRandomPatch() + currentDistance = distance(img[y:y+patchSize,x:x+patchSize], img[py:py+patchSize,px:px+patchSize]) + if currentDistance > firstDistance: + continue + currentFirstDistance = np.copy(currentDistance) + currentPatch, bestDistance = gradientDescent(x, y, bestPatch, bestDistance) + if currentDistance < bestDistance: + firstDistance = currentFirstDistance + bestPatch = currentPatch + bestDistance = currentDistance + img_copy[y:y+patchSize, x:x+patchSize] = fusion(img_copy[y:y+patchSize, x:x+patchSize],img[bestPatch[1]:bestPatch[1]+patchSize, bestPatch[0]:bestPatch[0]+patchSize]) + img[y1:y2,x1:x2] = img_copy[y1:y2,x1:x2] + return img + + +# Load the image using matplotlib +img = plt.imread('simson.png') + +if len(img.shape) == 2: + img = np.stack((img,)*3, axis=-1) + +def onselect(eclick, erelease): + x1, y1 = eclick.xdata, eclick.ydata + x2 = x1 + 150 + x2, y2 = erelease.xdata, erelease.ydata + + avg_color = np.mean(img, axis=(0, 1)) + + img_copy = np.copy(img) + img_copy[int(y1):int(y2), int(x1):int(x2)] = avg_color + res = patchMatch(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/boat.png b/boat.png new file mode 100644 index 0000000..61a1527 Binary files /dev/null and b/boat.png differ diff --git a/simson.png b/simson.png new file mode 100644 index 0000000..12c3361 Binary files /dev/null and b/simson.png differ