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.

120 lines
4.5 KiB

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