import numpy as np import cv2 class MaskedImage: DSCALE = 65535 base = [1.0, 0.99, 0.96, 0.83, 0.38, 0.11, 0.02, 0.005, 0.0006, 0.0001, 0] similarity = np.interp(np.linspace(0, 1, DSCALE + 1), np.linspace(0, 1, len(base)), base) def __init__(self,image=None,mask=None,width=None,height=None): if image is not None: self.image = image self.height, self.width = image.shape[:2] self.mask = mask return self.width = width self.height = height self.image = np.zeros((self.height, self.width, 3), dtype=np.uint8) self.mask = np.zeros((self.height, self.width), dtype=bool) def containsMask(self,x,y,patchSize): for dy in range(-patchSize,patchSize): for dx in range(-patchSize,patchSize): if (x+dx < 0 or self.width <= x+dx): continue if (y+dy < 0 or self.height <= y+dy): continue if self.mask[y+dy,x+dx]: 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()) def downsample(self): newW, newH = self.width // 2, self.height // 2 kernel = np.array([1, 5, 10, 10, 5, 1]) newimage = np.zeros((newH, newW, 3), dtype=np.uint8) newmask = np.zeros((newH, newW), dtype=bool) for y in range(0, self.height - 1, 2): for x in range(0, self.width - 1, 2): r, g, b, ksum, m = 0, 0, 0, 0, 0 for dy in range(-2, 4): yk = y + dy if (yk<0 or yk >= self.height): continue ky = kernel[2 + dy] for dx in range(-2, 4): xk = x + dx if (xk<0 or xk >= self.width): continue if self.mask[yk, xk]: continue k = kernel[2 + dx] * ky r += k * self.image[yk, xk, 0] g += k * self.image[yk, xk, 1] b += k * self.image[yk, xk, 2] ksum += k m += 1 if ksum > 0: newimage[y // 2, x // 2] = [r // ksum, g // ksum, b // ksum] newmask[y // 2, x // 2] = False else: newmask[y // 2, x // 2] = True return MaskedImage(image=newimage, mask=newmask) def upscale(self, newH, newW): newImage = MaskedImage(width=newW,height=newH) for y in range(newH): for x in range(newW): xs = int(x*self.width/newW) ys = int(y*self.height/newH) if not self.mask[ys,xs]: newImage.image[y,x,0] = self.image[ys,xs,0] newImage.image[y,x,1] = self.image[ys,xs,1] newImage.image[y,x,2] = self.image[ys,xs,2] newImage.mask[y,x] = False else: newImage.mask[y,x] = True return newImage