使用cv2.remap基于网格扭曲图像出现像素化,如何实现平滑扭曲?
如何用1/4尺寸网格实现图像平滑扭曲(解决cv2.remap像素化问题)
我有一个尺寸为图像1/4的网格,希望利用该网格信息对图像进行扭曲处理,但使用cv2.remap时得到的扭曲效果存在像素化问题。如何实现更平滑的扭曲效果?
效果对比
- 原图:

- 期望效果:

- 当前输出:

我的代码
img = np.array(Image.open('astronaut.jpg')) # Shape -> (512, 512, 3) mesh = Mesh('astronaut.msh').get_uvs() # Shape -> (128, 128, 2), 2 channels for x and y new_mesh = np.zeros((img.shape[1], img.shape[0], 2)) new_mesh[:,:,0] = np.repeat(np.repeat(mesh[:,:,0], 4, axis=0), 4, axis=1) new_mesh[:,:,1] = np.repeat(np.repeat(mesh[:,:,1], 4, axis=0), 4, axis=1) nh, nw = img.shape[:2] xs, ys = np.meshgrid(np.arange(0, nw), np.arange(0, nh)) xs = xs + new_mesh[:,:,0] * 4 # multiply by constant to modulate distort strength ys = ys + new_mesh[:,:,1] * 4 xs = np.float32(xs) ys = np.float32(ys) dst= cv2.remap(img.astype(np.uint8), xs, ys, cv2.INTER_CUBIC)
解决方法
问题出在用硬重复像素的方式放大网格,这种操作会让网格的位移信息呈块状阶梯分布,最终导致扭曲效果像素化。正确做法是对低分辨率网格做插值放大,生成连续平滑的位移场,步骤如下:
替换硬重复为插值放大
放弃np.repeat,改用OpenCV的cv2.resize,选择INTER_CUBIC(立方插值)或INTER_LINEAR(线性插值),让网格位移值平滑过渡:# 替换原new_mesh生成代码 new_mesh_x = cv2.resize(mesh[:,:,0], (nw, nh), interpolation=cv2.INTER_CUBIC) new_mesh_y = cv2.resize(mesh[:,:,1], (nw, nh), interpolation=cv2.INTER_CUBIC) new_mesh = np.stack([new_mesh_x, new_mesh_y], axis=-1)保留后续位移计算与映射
原代码中位移叠加、cv2.remap的部分无需修改,INTER_CUBIC插值方式已经能保证最终图像的平滑度。
修改后的完整代码:
import cv2 import numpy as np from PIL import Image img = np.array(Image.open('astronaut.jpg')) # Shape -> (512, 512, 3) mesh = Mesh('astronaut.msh').get_uvs() # Shape -> (128, 128, 2), 2 channels for x and y nh, nw = img.shape[:2] # 插值放大网格生成平滑位移场 new_mesh_x = cv2.resize(mesh[:,:,0], (nw, nh), interpolation=cv2.INTER_CUBIC) new_mesh_y = cv2.resize(mesh[:,:,1], (nw, nh), interpolation=cv2.INTER_CUBIC) new_mesh = np.stack([new_mesh_x, new_mesh_y], axis=-1) xs, ys = np.meshgrid(np.arange(0, nw), np.arange(0, nh)) xs = xs + new_mesh[:,:,0] * 4 # 调整扭曲强度 ys = ys + new_mesh[:,:,1] * 4 xs = np.float32(xs) ys = np.float32(ys) dst = cv2.remap(img.astype(np.uint8), xs, ys, cv2.INTER_CUBIC)
原理说明
np.repeat是直接复制每个网格点的位移值,生成的位移场是块状不连续的,扭曲时自然出现像素化边缘;cv2.resize的立方插值会根据周围网格点的位移值,计算出中间像素的过渡位移,生成连续平滑的位移场,最终扭曲效果就能和期望一致。
内容的提问来源于stack exchange,提问作者Diego Rodea
相关产品推荐
相关产品推荐

