You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
7.2 KiB
184 lines
7.2 KiB
from imageRelation import ImageRelation
|
|
from maskedImage import MaskedImage
|
|
import matplotlib.pyplot as plt
|
|
from tkinter import filedialog
|
|
import concurrent.futures
|
|
import tkinter as tk
|
|
import numpy as np
|
|
import pyautogui
|
|
import cv2
|
|
|
|
|
|
def read(file):
|
|
# fonction qui renvoit une image à partir de son chemin
|
|
img = plt.imread(file)
|
|
if img.dtype == np.float32: # si on est en valeur entre 0 et 1 au lieux de entre 0 et 255
|
|
img = (img * 255).astype(np.uint8)
|
|
img = img[:,:,0:3] # si on est en rgba
|
|
return img
|
|
|
|
def doTheInpainting(img,mask,radius):
|
|
# fonction qui effectue l'impainting
|
|
def maximizeForTheScale(scale):
|
|
# fonction interne qui effectue l'impainting pour une version réduite de l'image
|
|
iterEM = 1+2*scale
|
|
npPass = min(7,1+scale)
|
|
source = sourceToTarget.input
|
|
target = targetToSource.output
|
|
newTarget = None
|
|
for emloop in range(1,iterEM+1): # on fait les différentes pass pour augmenter petit à petit la qualité de l'image
|
|
# initialisation
|
|
if (newTarget != None):
|
|
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):
|
|
targetToSource.field[y,x] = (x,y,0)
|
|
# on cherche les patchs
|
|
targetToSource.findBestPatch(npPass)
|
|
# on crée la source et la target
|
|
upscaled = False
|
|
if scale>=1 and emloop == iterEM:
|
|
newSource = images[scale-1]
|
|
newTarget = target.upScale(newSource.height,newSource.width)
|
|
upscaled = True
|
|
else:
|
|
newSource = images[scale]
|
|
newTarget = target.copy()
|
|
upscaled = False
|
|
# on vote, on applique les votes puis on affiche les changements
|
|
vote = np.zeros((newTarget.width, newTarget.height, 4))
|
|
voteForPixels(targetToSource,vote,newSource,upscaled)
|
|
applyVote(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
|
|
|
|
initial = MaskedImage(img,mask)
|
|
images = [initial]
|
|
source = initial
|
|
while source.width>radius and source.height>radius: # crée les versions réduite en qualité de l'image
|
|
source = source.downScale()
|
|
images.append(source)
|
|
maxLevel = len(images)
|
|
|
|
for level in range(maxLevel-1,0,-1): # pour toutes les tailes de l'image, progressivement completer le trou à partir des images de qualité infèrieur déjà calculé
|
|
source = images[level]
|
|
if (level == maxLevel-1):
|
|
target = source.copy()
|
|
target.mask[0:target.height,0:target.width] = False
|
|
sourceToTarget = ImageRelation(source,target,radius)
|
|
sourceToTarget.randomize()
|
|
|
|
targetToSource = ImageRelation(target,source,radius)
|
|
targetToSource.randomize()
|
|
else:
|
|
newImRel = ImageRelation(source,target,radius)
|
|
newImRel.initializeFromImageRelation(sourceToTarget)
|
|
sourceToTarget = newImRel
|
|
|
|
newImRelRev = ImageRelation(target,source,radius)
|
|
newImRelRev.initializeFromImageRelation(targetToSource)
|
|
targetToSource = newImRelRev
|
|
target, sourceToTarget, targetToSource = maximizeForTheScale(level)
|
|
plt.imshow(target.image)
|
|
plt.pause(0.01)
|
|
return target.image
|
|
|
|
def voteForPixels(imRel, vote, source, upscale):
|
|
def voteForNb(nb):
|
|
# ajoute au vote pour toutes les pixels les valeurs déterminé lors de la recherche des patchs
|
|
wid = imRel.input.width//7
|
|
for y in range(imRel.input.height):
|
|
for x in range(nb*wid,(nb+1)*wid if nb != 7 else imRel.input.width): # divise par 8 l'image dans la largeur pour calculer ses 8 parties en même temps grâce aux threads
|
|
xp, yp, dp = imRel.field[y,x]
|
|
w = MaskedImage.similarity[dp]
|
|
for dy in range(-imRel.patchSize,imRel.patchSize): # pour toutes les pixels du patch qui ne sorte pas de l'image
|
|
ys = yp+dy
|
|
if not 0<=ys<imRel.input.height:
|
|
continue
|
|
yt = y+dy
|
|
if not 0<=yt<imRel.input.height:
|
|
continue
|
|
for dx in range(-imRel.patchSize,imRel.patchSize):
|
|
xs = xp+dx
|
|
if not 0<=xs<imRel.input.width:
|
|
continue
|
|
xt = x+dx
|
|
if not 0<=xt<imRel.input.width:
|
|
continue
|
|
if upscale: # si on change d'échelle prendre les 4 pixels autour pour faire comme un knn
|
|
addToVote(source,2*xs,2*ys,vote,2*xt,2*yt,w)
|
|
addToVote(source,2*xs+1,2*ys,vote,2*xt+1,2*yt,w)
|
|
addToVote(source,2*xs,2*ys+1,vote,2*xt,2*yt+1,w)
|
|
addToVote(source,2*xs+1,2*ys+1,vote,2*xt+1,2*yt+1,w)
|
|
else:
|
|
addToVote(source,xs,ys,vote,xt,yt,w)
|
|
# utilise une pool pour profiter des 8 threads de ma machine pour réduire le temp d'execution
|
|
pool = concurrent.futures.ThreadPoolExecutor(max_workers=8)
|
|
for i in range(8):
|
|
pool.submit(voteForNb,i)
|
|
pool.shutdown(wait=True)
|
|
|
|
def addToVote(src,xs,ys,vote,xd,yd,w):
|
|
# on ajoute au vote d'une pixel la couleur de la pixel asigné multiplié par un poid qui change en fonction de la similarité entre les deux pixels
|
|
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 applyVote(target,vote):
|
|
# appliquer les changements de pixels déterminé par les votes
|
|
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
|
|
|
|
|
|
def binDialog(titre,text):
|
|
# box de dialogue à choix bianire
|
|
pyautogui.FAILSAFE = True
|
|
return pyautogui.confirm(
|
|
text=text,
|
|
title=titre,
|
|
buttons=['Oui', 'Non']
|
|
)
|
|
|
|
def dialog(titre,text):
|
|
# box de dialogue à choix bianire
|
|
pyautogui.FAILSAFE = True
|
|
pyautogui.confirm(
|
|
text=text,
|
|
title=titre,
|
|
buttons=['Ok']
|
|
)
|
|
|
|
def stringDialog(titre, text):
|
|
# box de dialogue avec un input
|
|
pyautogui.FAILSAFE = True
|
|
return pyautogui.prompt(
|
|
text=text,
|
|
title=titre,
|
|
default=''
|
|
)
|
|
|
|
def selectImage():
|
|
# fonction de selection d'une image
|
|
root = tk.Tk()
|
|
root.withdraw() # Hide the main window
|
|
file_path = filedialog.askopenfilename(
|
|
title="Select an image",
|
|
filetypes=[
|
|
("Image files", "*.png *.jpg *.jpeg *.bmp")
|
|
]
|
|
)
|
|
return file_path |