iOS Swift:如何将检测到的图像局部从源点变形至目标点?
解决
WarpGeometryFilter局部图像变形问题 问题根源
你当前的错误在于:SKWarpGeometryGrid需要的是覆盖整个图像的完整网格顶点坐标,而非仅目标区域的几个检测点。只传入球体的6个点时,剩余网格点会默认使用图像边缘坐标,导致整个图像被错误拉扯。
正确实现步骤
要仅让蓝色球体区域变形,需生成覆盖全图的网格,仅对球体内的顶点设置偏移,其余顶点保持源坐标不变:
- 创建覆盖整个图像的规则网格(行列数决定变形精度)
- 识别网格中属于蓝色球体区域的顶点
- 对这些顶点应用目标偏移,其余顶点源/目标坐标一致
完整代码示例
// 1. 定义网格参数:行列数越大变形越精细,性能消耗越高 let gridColumns = 20 let gridRows = 20 // 2. 生成覆盖全图的源网格坐标(归一化范围0~1) var sourcePositions: [vector_float2] = [] for row in 0...gridRows { let y = Float(row) / Float(gridRows) for column in 0...gridColumns { let x = Float(column) / Float(gridColumns) sourcePositions.append(vector_float2(x: x, y: y)) } } // 3. 初始化目标网格,默认与源网格一致 var destinationPositions = sourcePositions // 4. 计算球体的整体偏移量(从检测点取平均偏移) let offsetX = ballVectorNewArray[0].x - ballVectorArray[0].x let offsetY = ballVectorNewArray[0].y - ballVectorArray[0].y // 5. 计算球体的包围盒,用于判断网格点是否在球体内 let ballMinX = ballVectorArray.map { $0.x }.min()! let ballMaxX = ballVectorArray.map { $0.x }.max()! let ballMinY = ballVectorArray.map { $0.y }.min()! let ballMaxY = ballVectorArray.map { $0.y }.max()! // 6. 遍历网格点,对球体内的点应用偏移 for (index, point) in sourcePositions.enumerated() { // 判断点是否在球体包围盒内(可替换为基于中心+半径的精确判断) if point.x >= ballMinX && point.x <= ballMaxX && point.y >= ballMinY && point.y <= ballMaxY { destinationPositions[index] = vector_float2(x: point.x + offsetX, y: point.y + offsetY) } } // 7. 创建网格并应用滤镜 let warpGeometry = SKWarpGeometryGrid(columns: gridColumns, rows: gridRows, sourcePositions: sourcePositions, destinationPositions: destinationPositions) let filter = WarpGeometryFilter(device: MTLCreateSystemDefaultDevice()!) filter.setValue(sourceImage, forKey: kCIInputImageKey) filter.setValue(warpGeometry, forKey: kCIInputWarpGeometryKey) let result = filter.outputImage!
优化建议
- 若要更自然的过渡效果,可替换包围盒判断为距离加权偏移:计算网格点到球体中心的距离,距离越近偏移量越大,边缘区域平滑过渡,避免生硬的变形边界。
- 根据实际需求调整网格行列数:追求精细变形则增大数值,注重性能则减小数值。
内容的提问来源于stack exchange,提问作者Diana
相关产品推荐
相关产品推荐

