import numpy as np import cv2 def crop_from_points(img, corners, make_square=False): cnt = np.array([corners[0], corners[1], corners[2], corners[3]]) rect = cv2.minAreaRect(cnt) center, size, theta = rect # Angle correction if theta < -45: theta += 90 cnt = np.array([corners[1], corners[3], corners[0], corners[2]]) rect = (center, size, theta) box = cv2.boxPoints(rect) box = np.int0(box) height = int(rect[1][0]) width = int(rect[1][1]) else: rect = (center, size, theta) box = cv2.boxPoints(rect) box = np.int0(box) height = int(rect[1][1]) width = int(rect[1][0]) src_pts = np.float32([corners[0],corners[1],corners[2],corners[3]]) dst_pts = np.float32([[0,0],[width,0],[0,height],[width,height]]) M = cv2.getPerspectiveTransform(src_pts, dst_pts) warped = cv2.warpPerspective(img, M, (width, height)) transformation_data = { 'matrix': M, 'original_shape': (height, width) } return warped, transformation_data def perspective_transform(img, transformation_matrix, original_shape=None, full_image_shape=(480,640)): h, w = full_image_shape[0], full_image_shape[1] warped = cv2.warpPerspective(img, transformation_matrix, (w, h)) return warped def blend_non_transparent(sprite, background_img): gray_overlay = cv2.cvtColor(background_img, cv2.COLOR_BGR2GRAY) overlay_mask = cv2.threshold(gray_overlay, 1, 255, cv2.THRESH_BINARY)[1] overlay_mask = cv2.erode(overlay_mask, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))) overlay_mask = cv2.blur(overlay_mask, (3, 3)) background_mask = 255 - overlay_mask overlay_mask = cv2.cvtColor(overlay_mask, cv2.COLOR_GRAY2BGR) background_mask = cv2.cvtColor(background_mask, cv2.COLOR_GRAY2BGR) sprite_part = (sprite * (1 / 255.0)) * (background_mask * (1 / 255.0)) overlay_part = (background_img * (1 / 255.0)) * (overlay_mask * (1 / 255.0)) return np.uint8(cv2.addWeighted(sprite_part, 255.0, overlay_part, 255.0, 0.0)) def overlay_transparent(background, overlay, y, x): if y < 0: y = 0 if x < 0: x = 0 background_width = background.shape[1] background_height = background.shape[0] if x >= background_width or y >= background_height: return background h, w = overlay.shape[0], overlay.shape[1] if x + w > background_width: w = background_width - x overlay = overlay[:, :w] if y + h > background_height: h = background_height - y overlay = overlay[:h] if overlay.shape[2] < 4: overlay = np.concatenate( [ overlay, np.ones((overlay.shape[0], overlay.shape[1], 1), dtype=overlay.dtype) * 255 ], axis=2, ) overlay_image = overlay[..., :3] mask = overlay[..., 3:] / 255.0 background[y:y+h, x:x+w] = (1.0 - mask) * background[y:y+h, x:x+w] + mask * overlay_image return background def resize_transparent_sprite(image, width=None, height=None, inter=cv2.INTER_AREA): # split image and alpha channel # resize them separately # join them other_channels = alpha_channel = image[:,:,:3] alpha_channel = image[:,:,3] dim = None (h, w) = image.shape[:2] # if both the width and height are None, then return the # original image if width is None and height is None: return image # check to see if the width is None if width is None: # calculate the ratio of the height and construct the # dimensions r = height / float(h) dim = (int(w * r), height) # otherwise, the height is None else: # calculate the ratio of the width and construct the # dimensions r = width / float(w) dim = (width, int(h * r)) image_resized = cv2.resize(other_channels, dim, interpolation=inter) alpha_resized = cv2.resize(alpha_channel, dim, interpolation=inter) new_image = np.empty((dim[1], dim[0], 4)) new_image[:, :, :3] = image_resized new_image[:, :, 3] = alpha_resized return new_image class Singleton: """ A non-thread-safe helper class to ease implementing singletons. This should be used as a decorator -- not a metaclass -- to the class that should be a singleton. The decorated class can define one `__init__` function that takes only the `self` argument. Also, the decorated class cannot be inherited from. Other than that, there are no restrictions that apply to the decorated class. To get the singleton instance, use the `instance` method. Trying to use `__call__` will result in a `TypeError` being raised. """ def __init__(self, decorated): self._decorated = decorated def instance(self): """ Returns the singleton instance. Upon its first call, it creates a new instance of the decorated class and calls its `__init__` method. On all subsequent calls, the already created instance is returned. """ try: return self._instance except AttributeError: self._instance = self._decorated() return self._instance def __call__(self): raise TypeError('Singletons must be accessed through `instance()`.') def __instancecheck__(self, inst): return isinstance(inst, self._decorated)