Spaces:
Build error
Build error
| import cv2 | |
| import base64 | |
| import numpy as np | |
| def laplacian_blending(A, B, m, num_levels=7): | |
| assert A.shape == B.shape | |
| assert B.shape == m.shape | |
| height = m.shape[0] | |
| width = m.shape[1] | |
| size_list = np.array([4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192]) | |
| size = size_list[np.where(size_list > max(height, width))][0] | |
| GA = np.zeros((size, size, 3), dtype=np.float32) | |
| GA[:height, :width, :] = A | |
| GB = np.zeros((size, size, 3), dtype=np.float32) | |
| GB[:height, :width, :] = B | |
| GM = np.zeros((size, size, 3), dtype=np.float32) | |
| GM[:height, :width, :] = m | |
| gpA = [GA] | |
| gpB = [GB] | |
| gpM = [GM] | |
| for i in range(num_levels): | |
| GA = cv2.pyrDown(GA) | |
| GB = cv2.pyrDown(GB) | |
| GM = cv2.pyrDown(GM) | |
| gpA.append(np.float32(GA)) | |
| gpB.append(np.float32(GB)) | |
| gpM.append(np.float32(GM)) | |
| lpA = [gpA[num_levels-1]] | |
| lpB = [gpB[num_levels-1]] | |
| gpMr = [gpM[num_levels-1]] | |
| for i in range(num_levels-1,0,-1): | |
| LA = np.subtract(gpA[i-1], cv2.pyrUp(gpA[i])) | |
| LB = np.subtract(gpB[i-1], cv2.pyrUp(gpB[i])) | |
| lpA.append(LA) | |
| lpB.append(LB) | |
| gpMr.append(gpM[i-1]) | |
| LS = [] | |
| for la,lb,gm in zip(lpA,lpB,gpMr): | |
| ls = la * gm + lb * (1.0 - gm) | |
| LS.append(ls) | |
| ls_ = LS[0] | |
| for i in range(1,num_levels): | |
| ls_ = cv2.pyrUp(ls_) | |
| ls_ = cv2.add(ls_, LS[i]) | |
| ls_ = ls_[:height, :width, :] | |
| #ls_ = (ls_ - np.min(ls_)) * (255.0 / (np.max(ls_) - np.min(ls_))) | |
| return ls_.clip(0, 255) | |
| def mask_crop(mask, crop): | |
| top, bottom, left, right = crop | |
| shape = mask.shape | |
| top = int(top) | |
| bottom = int(bottom) | |
| if top + bottom < shape[1]: | |
| if top > 0: mask[:top, :] = 0 | |
| if bottom > 0: mask[-bottom:, :] = 0 | |
| left = int(left) | |
| right = int(right) | |
| if left + right < shape[0]: | |
| if left > 0: mask[:, :left] = 0 | |
| if right > 0: mask[:, -right:] = 0 | |
| return mask | |
| def create_image_grid(images, size=128): | |
| num_images = len(images) | |
| num_cols = int(np.ceil(np.sqrt(num_images))) | |
| num_rows = int(np.ceil(num_images / num_cols)) | |
| grid = np.zeros((num_rows * size, num_cols * size, 3), dtype=np.uint8) | |
| for i, image in enumerate(images): | |
| row_idx = (i // num_cols) * size | |
| col_idx = (i % num_cols) * size | |
| image = cv2.resize(image.copy(), (size,size)) | |
| if image.dtype != np.uint8: | |
| image = (image.astype('float32') * 255).astype('uint8') | |
| if image.ndim == 2: | |
| image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) | |
| grid[row_idx:row_idx + size, col_idx:col_idx + size] = image | |
| return grid | |
| def paste_to_whole(foreground, background, matrix, mask=None, crop_mask=(0,0,0,0), blur_amount=0.1, erode_amount = 0.15, blend_method='linear'): | |
| inv_matrix = cv2.invertAffineTransform(matrix) | |
| fg_shape = foreground.shape[:2] | |
| bg_shape = (background.shape[1], background.shape[0]) | |
| foreground = cv2.warpAffine(foreground, inv_matrix, bg_shape, borderValue=0.0, borderMode=cv2.BORDER_REPLICATE) | |
| if mask is None: | |
| mask = np.full(fg_shape, 1., dtype=np.float32) | |
| mask = mask_crop(mask, crop_mask) | |
| mask = cv2.warpAffine(mask, inv_matrix, bg_shape, borderValue=0.0) | |
| else: | |
| assert fg_shape == mask.shape[:2], "foreground & mask shape mismatch!" | |
| mask = mask_crop(mask, crop_mask).astype('float32') | |
| mask = cv2.warpAffine(mask, inv_matrix, (background.shape[1], background.shape[0]), borderValue=0.0) | |
| _mask = mask.copy() | |
| _mask[_mask > 0.05] = 1. | |
| non_zero_points = cv2.findNonZero(_mask) | |
| _, _, w, h = cv2.boundingRect(non_zero_points) | |
| mask_size = int(np.sqrt(w * h)) | |
| if erode_amount > 0: | |
| kernel_size = max(int(mask_size * erode_amount), 1) | |
| structuring_element = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size)) | |
| mask = cv2.erode(mask, structuring_element) | |
| if blur_amount > 0: | |
| kernel_size = max(int(mask_size * blur_amount), 3) | |
| if kernel_size % 2 == 0: | |
| kernel_size += 1 | |
| mask = cv2.GaussianBlur(mask, (kernel_size, kernel_size), 0) | |
| mask = np.tile(np.expand_dims(mask, axis=-1), (1, 1, 3)) | |
| if blend_method == 'laplacian': | |
| composite_image = laplacian_blending(foreground, background, mask.clip(0,1), num_levels=4) | |
| else: | |
| composite_image = mask * foreground + (1 - mask) * background | |
| return composite_image.astype("uint8").clip(0, 255) | |
| def image_mask_overlay(img, mask): | |
| img = img.astype('float32') / 255. | |
| img *= (mask + 0.25).clip(0, 1) | |
| img = np.clip(img * 255., 0., 255.).astype('uint8') | |
| return img | |
| def resize_with_padding(img, expected_size=(640, 360), color=(0, 0, 0), max_flip=False): | |
| original_height, original_width = img.shape[:2] | |
| if max_flip and original_height > original_width: | |
| expected_size = (expected_size[1], expected_size[0]) | |
| aspect_ratio = original_width / original_height | |
| new_width = expected_size[0] | |
| new_height = int(new_width / aspect_ratio) | |
| if new_height > expected_size[1]: | |
| new_height = expected_size[1] | |
| new_width = int(new_height * aspect_ratio) | |
| resized_img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_AREA) | |
| canvas = cv2.copyMakeBorder(resized_img, | |
| top=(expected_size[1] - new_height) // 2, | |
| bottom=(expected_size[1] - new_height + 1) // 2, | |
| left=(expected_size[0] - new_width) // 2, | |
| right=(expected_size[0] - new_width + 1) // 2, | |
| borderType=cv2.BORDER_CONSTANT, value=color) | |
| return canvas | |
| def create_image_grid(images, size=128): | |
| num_images = len(images) | |
| num_cols = int(np.ceil(np.sqrt(num_images))) | |
| num_rows = int(np.ceil(num_images / num_cols)) | |
| grid = np.zeros((num_rows * size, num_cols * size, 3), dtype=np.uint8) | |
| for i, image in enumerate(images): | |
| row_idx = (i // num_cols) * size | |
| col_idx = (i % num_cols) * size | |
| image = cv2.resize(image.copy(), (size,size)) | |
| if image.dtype != np.uint8: | |
| image = (image.astype('float32') * 255).astype('uint8') | |
| if image.ndim == 2: | |
| image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) | |
| grid[row_idx:row_idx + size, col_idx:col_idx + size] = image | |
| return grid | |
| def image_to_html(img, size=(640, 360), extension="jpg"): | |
| if img is not None: | |
| img = resize_with_padding(img, expected_size=size) | |
| buffer = cv2.imencode(f".{extension}", img)[1] | |
| base64_data = base64.b64encode(buffer.tobytes()) | |
| imgbs64 = f"data:image/{extension};base64," + base64_data.decode("utf-8") | |
| html = '<div style="display: flex; justify-content: center; align-items: center; width: 100%;">' | |
| html += f'<img src={imgbs64} alt="No Preview" style="max-width: 100%; max-height: 100%;">' | |
| html += '</div>' | |
| return html | |
| return None | |
| def mix_two_image(a, b, opacity=1.): | |
| a_dtype = a.dtype | |
| b_dtype = b.dtype | |
| a = a.astype('float32') | |
| b = b.astype('float32') | |
| a = cv2.resize(a, (b.shape[0], b.shape[1])) | |
| opacity = min(max(opacity, 0.), 1.) | |
| mixed_img = opacity * b + (1 - opacity) * a | |
| return mixed_img.astype(a_dtype) | |
| resolution_map = { | |
| "Original": None, | |
| "240p": (426, 240), | |
| "360p": (640, 360), | |
| "480p": (854, 480), | |
| "720p": (1280, 720), | |
| "1080p": (1920, 1080), | |
| "1440p": (2560, 1440), | |
| "2160p": (3840, 2160), | |
| } | |
| def resize_image_by_resolution(img, quality): | |
| resolution = resolution_map.get(quality, None) | |
| if resolution is None: | |
| return img | |
| h, w = img.shape[:2] | |
| if h > w: | |
| ratio = resolution[0] / h | |
| else: | |
| ratio = resolution[0] / w | |
| new_h, new_w = int(h * ratio), int(w * ratio) | |
| img = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_AREA) | |
| return img | |
| def fast_pil_encode(pil_image): | |
| image_arr = np.asarray(pil_image)[:,:,::-1] | |
| buffer = cv2.imencode('.jpg', image_arr)[1] | |
| base64_data = base64.b64encode(buffer.tobytes()) | |
| return "data:image/jpg;base64," + base64_data.decode("utf-8") | |
| def fast_numpy_encode(img_array): | |
| buffer = cv2.imencode('.jpg', img_array)[1] | |
| base64_data = base64.b64encode(buffer.tobytes()) | |
| return "data:image/jpg;base64," + base64_data.decode("utf-8") | |
| crf_quality_by_resolution = { | |
| 240: {"poor": 45, "low": 35, "medium": 28, "high": 23, "best": 20}, | |
| 360: {"poor": 35, "low": 28, "medium": 23, "high": 20, "best": 18}, | |
| 480: {"poor": 28, "low": 23, "medium": 20, "high": 18, "best": 16}, | |
| 720: {"poor": 23, "low": 20, "medium": 18, "high": 16, "best": 14}, | |
| 1080: {"poor": 20, "low": 18, "medium": 16, "high": 14, "best": 12}, | |
| 1440: {"poor": 18, "low": 16, "medium": 14, "high": 12, "best": 10}, | |
| 2160: {"poor": 16, "low": 14, "medium": 12, "high": 10, "best": 8} | |
| } | |
| def get_crf_for_resolution(resolution, quality): | |
| available_resolutions = list(crf_quality_by_resolution.keys()) | |
| closest_resolution = min(available_resolutions, key=lambda x: abs(x - resolution)) | |
| return crf_quality_by_resolution[closest_resolution][quality] |