Source code for pyflowreg.util.resize_util

import cv2
import numpy as np
from numba import njit
from skimage.transform import resize as ski_resize

A = -0.75


[docs] def resize_image_skimage(image, size): """ Resize an image to the specified size using the given interpolation method. Parameters: - image: Input image to be resized. - size: Tuple (width, height) specifying the new size. - interpolation: Interpolation method to use for resizing. Returns: - Resized image. """ img = ski_resize( image, (size[1], size[0]), order=3, mode="edge", anti_aliasing=True ) return img
[docs] def resize_image_cv2(image, size): """ Resize an image to the specified size using the given interpolation method. Parameters: - image: Input image to be resized. - size: Tuple (width, height) specifying the new size. - interpolation: Interpolation method to use for resizing. Returns: - Resized image. """ img = cv2.resize(image, (size[1], size[0]), interpolation=cv2.INTER_LANCZOS4) return img
[docs] def resize_image_cv2_aa_gauss(image, size): h_orig, w_orig = image.shape[:2] h_new, w_new = size[:2] scale = min(h_new / h_orig, w_new / w_orig) if scale < 1: sigma = 0.6 / scale ksize = int(2 * np.ceil(2 * sigma) + 1) image = cv2.GaussianBlur(image, (ksize, ksize), sigma) img = cv2.resize(image, (size[1], size[0]), interpolation=cv2.INTER_CUBIC) return img
[docs] def imresize_cv2_aa_gauss_sep(img, size): h, w = img.shape[:2] sx, sy = size[1] / w, size[0] / h scale = min(sx, sy) if scale < 1: sigma = 0.6 / scale k = int(2 * np.ceil(2 * sigma) + 1) g = cv2.getGaussianKernel(k, sigma) img = cv2.sepFilter2D(img, -1, g, g, borderType=cv2.BORDER_REFLECT101) return cv2.resize(img, size[1::-1], interpolation=cv2.INTER_CUBIC)
@njit(inline="always") def _cubic(x): ax = abs(x) if ax < 1.0: return (A + 2.0) * ax**3 - (A + 3.0) * ax**2 + 1.0 elif ax < 2.0: return A * ax**3 - 5.0 * A * ax**2 + 8.0 * A * ax - 4.0 * A else: return 0.0 @njit(fastmath=True, cache=True) def _fill_tables(idx, wt, in_len, out_len, s, w, scaled): P = idx.shape[1] for i in range(out_len): x = (i + 0.5) / s - 0.5 left = int(np.floor(x - 0.5 * w)) sumw = 0.0 for p in range(P): j = left + p jj = 0 if j < 0 else (in_len - 1 if j > in_len - 1 else j) idx[i, p] = jj d = x - j wgt = s * _cubic(s * d) if scaled else _cubic(d) wt[i, p] = wgt sumw += wgt inv = 1.0 / sumw for p in range(P): wt[i, p] *= inv def _precompute(in_len, out_len): scale = out_len / in_len if scale < 1.0: W = 4.0 / scale shrink = True else: W = 4.0 shrink = False P = int(np.ceil(W)) + 1 idx = np.empty((out_len, P), np.int32) wt = np.empty((out_len, P), np.float32) _fill_tables(idx, wt, in_len, out_len, scale, W, shrink) return idx, wt @njit(fastmath=True, cache=True) def _resize_h(src, idx, wt): h = src.shape[0] ow, P = wt.shape dst = np.empty((h, ow), src.dtype) for y in range(h): for x in range(ow): s = 0.0 for p in range(P): s += src[y, idx[x, p]] * wt[x, p] dst[y, x] = s return dst @njit(fastmath=True, cache=True) def _resize_v(src, idx, wt): w = src.shape[1] oh, P = wt.shape dst = np.empty((oh, w), src.dtype) for x in range(w): for y in range(oh): s = 0.0 for p in range(P): s += src[idx[y, p], x] * wt[y, p] dst[y, x] = s return dst
[docs] def imresize_numba(img, size): oh, ow = size[:2] work = img.astype(np.float32, copy=False) idx_x, wt_x = _precompute(work.shape[1], ow) idx_y, wt_y = _precompute(work.shape[0], oh) if work.ndim == 2: out = np.empty((oh, ow), np.float32) tmp = _resize_h(work, idx_x, wt_x) out[:] = _resize_v(tmp, idx_y, wt_y) else: ch = work.shape[2] out = np.empty((oh, ow, ch), np.float32) for c in range(ch): # 2-D slice per kernel call tmp = _resize_h(work[:, :, c], idx_x, wt_x) out[:, :, c] = _resize_v(tmp, idx_y, wt_y) return out.astype(img.dtype, copy=False)
[docs] def resize_image_cv2_aa_blur(image, size): h_orig, w_orig = image.shape[:2] h_new, w_new = size[:2] if h_new < h_orig or w_new < w_orig: # Box filter - much faster than Gaussian, still removes aliasing scale = max(h_orig / h_new, w_orig / w_new) ksize = int(scale) | 1 # Ensure odd if ksize > 1: image = cv2.blur(image, (ksize, ksize)) img = cv2.resize(image, (size[1], size[0]), interpolation=cv2.INTER_CUBIC) return img
@njit(inline="always") def _reflect_idx(j, n): if n <= 1: return 0 while j < 0 or j >= n: if j < 0: j = -j - 1 else: j = 2 * n - 1 - j return j @njit(fastmath=True, cache=True) def _fill_tables_fused_gauss_cubic_reflect(idx, wt, in_len, out_len, scale, g, R): P = 2 * R + 4 for i in range(out_len): x = (i + 0.5) / scale - 0.5 left = int(np.floor(x - 2.0)) - R ssum = 0.0 for p in range(P): j = left + p jj = _reflect_idx(j, in_len) idx[i, p] = jj d = x - j acc = 0.0 for u in range(-R, R + 1): acc += g[u + R] * _cubic(d - u) wt[i, p] = acc ssum += acc inv = 1.0 / ssum for p in range(P): wt[i, p] *= inv def _precompute_fused_gauss_cubic(in_len, out_len, sigma): scale = out_len / in_len if sigma <= 0.0: R = 0 g = np.array([1.0], dtype=np.float32) else: R = int(np.ceil(2.0 * sigma)) x = np.arange(-R, R + 1, dtype=np.float32) g = np.exp(-0.5 * (x / sigma) ** 2).astype(np.float32) g /= g.sum() idx = np.empty((out_len, 2 * R + 4), np.int32) wt = np.empty((out_len, 2 * R + 4), np.float32) _fill_tables_fused_gauss_cubic_reflect(idx, wt, in_len, out_len, scale, g, R) return idx, wt
[docs] def imresize_fused_gauss_cubic(img, size, sigma_coeff=0.6, per_axis=False): oh, ow = size[:2] x = img.astype(np.float32, copy=False) sy = oh / x.shape[0] sx = ow / x.shape[1] if per_axis: sigx = sigma_coeff / sx if sx < 1.0 else 0.0 sigy = sigma_coeff / sy if sy < 1.0 else 0.0 else: s = sy if sy < sx else sx sigx = sigy = (sigma_coeff / s) if s < 1.0 else 0.0 idx_x, wt_x = _precompute_fused_gauss_cubic(x.shape[1], ow, sigx) idx_y, wt_y = _precompute_fused_gauss_cubic(x.shape[0], oh, sigy) if x.ndim == 2: tmp = _resize_h(x, idx_x, wt_x) y = _resize_v(tmp, idx_y, wt_y) else: c = x.shape[2] y = np.empty((oh, ow, c), np.float32) for k in range(c): tmp = _resize_h(x[:, :, k], idx_x, wt_x) y[:, :, k] = _resize_v(tmp, idx_y, wt_y) return y.astype(img.dtype, copy=False)