无缝平缝贴图的生成与接缝修补:从边缘扩散到泊松融合
在 3D 渲染与环境美术管线中,地表、砖墙、岩石等大面积材质都需要进行平铺(Tiling)。无论是通过 AI 扩散模型(如 Stable Diffusion)生成的贴图,还是无人机航拍实采的纹理,直接平铺都会在四周边框出现刺眼的几何缝隙与色调断层。
传统 Photoshop 中的“位移 + 仿制图章”依赖人工手动修补,无法集成到全自动 PCG 或实时材质生成管线中。从算法角度出发,消除贴图接缝有两种核心思路:基于几何加权的边缘渐变扩散(Alpha Feathered Wrap Blending),以及基于梯度域优化的泊松图像融合(Poisson Image Blending)。
贴图环绕位移与接缝的本质
接缝产生的根本原因是图像左右边缘 $I(0, y)$ 与 $I(W-1, y)$、上下边缘 $I(x, 0)$ 与 $I(x, H-1)$ 存在像素值与梯度差。
通过对图像进行半宽半高位移(Wrap Offset),将原本在四周的四条外边界平移到图像正中央呈十字形十字交叉线:
$$(x', y') = ((x + W/2) \\pmod W, (y + H/2) \\pmod H)$$
接缝修复的目标,就是在保持四周边沿绝对连续的前提下,将十字交叉接缝处的过渡处理得平滑无痕。
方案一:基于距离场的边缘扩散融合(快速但易模糊)
边缘扩散法通过在十字接缝处定义一个过渡宽度(Band Width $B$),利用线性或余弦插值权重将边缘像素与对应内侧像素进行加权平均。
这种方法的优点是计算极快,仅需几个片元指令即可在 GPU 上完成;缺点是在高频细节纹理(如鹅卵石、裂纹砖石)上,线性叠加会产生明显的半透明重影与模糊软化。
import numpy as np
def make_seamless_feather(image: np.ndarray, overlap: float = 0.15) -> np.ndarray:
"""
基于余弦权重的边缘无缝融合
:param image: 输入图像 (H, W, C), float32 [0, 1]
:param overlap: 重叠过渡区域占比 (0.0 – 0.5)
"""
h, w, c = image.shape
ow = int(w * overlap)
oh = int(h * overlap)
# 构造水平与垂直平滑权重矩阵
x = np.linspace(0, 1, ow)
w_weight = 0.5 * (1 – np.cos(np.pi * x)) # 余弦平滑曲线
y = np.linspace(0, 1, oh)
h_weight = 0.5 * (1 – np.cos(np.pi * y))
# 先做 Wrap Offset 将边缘移到中心
shifted = np.roll(np.roll(image, shift=w // 2, axis=1), shift=h // 2, axis=0)
# 对十字交叉区域进行权重平滑混合
# … 在过渡区混合原始边沿信息 …
return shifted
方案二:梯度域泊松融合(保持高频细节与光照一致)
为了避免融合区域变模糊,必须在**梯度域(Gradient Domain)**进行求解。泊松融合的核心思想是:保持待修补区域内的细节纹理梯度 $\\mathbf{v} = \\nabla I$ 不变,同时强行约束修补区域边界与目标背景完全吻合。
数学上,这等价于求解带有狄利利条件(Dirichlet Boundary Conditions)的泊松偏微分方程:
$$\\Delta f = \\operatorname{div} \\mathbf{v} \\quad \\text{over } \\Omega, \\quad \\text{with } f|{\\partial \\Omega} = f^*|{\\partial \\Omega}$$
其中:
- $\\Delta = \\frac{\\partial^2}{\\partial x^2} + \\frac{\\partial^2}{\\partial y^2}$ 为拉普拉斯算子(Laplace Operator)。
- $\\mathbf{v}$ 是在十字接缝处采样的引导向量场(通常直接取原图位移后的梯度)。
- $\\partial \\Omega$ 为缝隙过渡带的外边界。
在离散网格上,拉普拉斯方程表现为一个巨大的稀疏线性方程组 $A \\mathbf{x} = \\mathbf{b}$,每个内部像素满足五点离散差分格式:
$$4 f_{i,j} – f_{i-1,j} – f_{i+1,j} – f_{i,j-1} – f_{i,j+1} = \\operatorname{div} \\mathbf{v}(i, j)$$
泊松无缝贴图修补的工程实现
下面给出利用 SciPy 稀疏矩阵求解器实现的无缝贴图修补流水线:
import numpy as np
import scipy.sparse as sp
import scipy.sparse.linalg as splinalg
import cv2
def make_seamless_poisson(img: np.ndarray, blend_width: int = 32) -> np.ndarray:
"""
使用泊松融合消除位移后的十字接缝
:param img: 输入图像 float32, 范围 [0, 1]
:param blend_width: 十字接缝处的修补带半宽 (像素)
"""
h, w, c = img.shape
# 1. 环绕位移,使外边框对齐到内部
shifted = np.roll(np.roll(img, shift=w // 2, axis=1), shift=h // 2, axis=0)
# 2. 构建十字接缝修补 Mask (1 代表待修补区域,0 代表绝对保持区域)
mask = np.zeros((h, w), dtype=np.uint8)
cx, cy = w // 2, h // 2
mask[:, max(0, cx – blend_width):min(w, cx + blend_width)] = 1
mask[max(0, cy – blend_width):min(h, cy + blend_width), :] = 1
# 3. 计算引导梯度场 (采用原图未位移时的边界无缝梯度)
# 为每个通道独立求解泊松方程
result = np.zeros_like(shifted)
# 建立未知数像素索引映射
unknown_indices = np.where(mask == 1)
num_unknowns = len(unknown_indices[0])
coord_to_idx = -np.ones((h, w), dtype=np.int32)
for idx, (y, x) in enumerate(zip(unknown_indices[0], unknown_indices[1])):
coord_to_idx[y, x] = idx
# 构建稀疏拉普拉斯矩阵 A
A = sp.lil_matrix((num_unknowns, num_unknowns), dtype=np.float32)
for idx, (y, x) in enumerate(zip(unknown_indices[0], unknown_indices[1])):
A[idx, idx] = 4.0
neighbors = [(y – 1, x), (y + 1, x), (y, x – 1), (y, x + 1)]
for ny, nx in neighbors:
ny = ny % h
nx = nx % w
if mask[ny, nx] == 1:
n_idx = coord_to_idx[ny, nx]
A[idx, n_idx] = -1.0
A = A.tocsr()
# 求解每个颜色通道
for ch in range(c):
b = np.zeros(num_unknowns, dtype=np.float32)
channel_data = shifted[:, :, ch]
# 计算离散散度与边界条件
for idx, (y, x) in enumerate(zip(unknown_indices[0], unknown_indices[1])):
# 从位移原图中计算目标拉普拉斯值
div = 4.0 * channel_data[y, x] – (
channel_data[(y – 1) % h, x] +
channel_data[(y + 1) % h, x] +
channel_data[y, (x – 1) % w] +
channel_data[y, (x + 1) % w]
)
# 边界固定值约束
neighbors = [(y – 1, x), (y + 1, x), (y, x – 1), (y, x + 1)]
for ny, nx in neighbors:
ny = ny % h
nx = nx % w
if mask[ny, nx] == 0:
div += channel_data[ny, nx]
b[idx] = div
# 使用共轭梯度法快速求解稀疏系统
x_sol, _ = splinalg.cg(A, b, maxiter=200, tol=1e-5)
reconstructed = channel_data.copy()
for idx, (y, x) in enumerate(zip(unknown_indices[0], unknown_indices[1])):
reconstructed[y, x] = x_sol[idx]
result[:, :, ch] = np.clip(reconstructed, 0.0, 1.0)
return result
两类算法的性能与适用场景权衡
| 计算复杂度 | $O(N)$,简单线性插值 | $O(N^{1.5})$,稀疏线性系统求解 |
| GPU 实时性 | 极佳(可在片元着色器 0.05ms 内完成) | 较重(通常在离线烘焙或 Compute Shader 多网格迭代) |
| 高频边缘保持 | 易产生模糊光晕与双重重影 | 极佳,完整保留砂石、砖缝等高频拓扑 |
| 大尺度光照平滑 | 无法消除全局明暗渐变色差 | 自动扩散低频色彩,消除阴阳脸 |
在现代资产自动化流水线中,对于法线贴图(Normal Map)和粗糙度贴图(Roughness Map),由于法线向量具有归一化几何约束,通常采用扩散与切线重归一化;而对于高动态漫反射贴图(Albedo / Base Color),泊松融合则是消除光照不均与边缘色差的工业标准利器。
网硕互联帮助中心



评论前必须登录!
注册