Swift实现视频指定颜色透明化并保存编辑后的视频
在Swift中实现视频指定颜色透明化并保存
核心思路
要实现视频指定颜色透明,本质是对每一帧图像做颜色抠图处理,生成带Alpha通道的视频帧后重新编码合成。核心依赖AVFoundation(视频读写与合成)和CoreImage(帧图像滤镜处理)框架,步骤如下:
- 读取原视频轨道
- 用CoreImage滤镜将目标颜色区域转为透明
- 生成带Alpha通道的视频合成项用于播放或导出
完整实现代码
1. 颜色抠图滤镜工具函数
封装生成颜色抠图滤镜的逻辑,可通过容差参数控制颜色匹配范围:
import AVFoundation import CoreImage func createColorKeyFilter(targetColor: UIColor, tolerance: CGFloat = 0.1) -> CIFilter? { guard let ciColor = CIColor(color: targetColor) else { return nil } // 1. 计算颜色差值,分离目标颜色区域 let colorMatrixFilter = CIFilter(name: "CIColorMatrix")! let redVector = CIVector(x: 1, y: 0, z: 0, w: -ciColor.red) let greenVector = CIVector(x: 0, y: 1, z: 0, w: -ciColor.green) let blueVector = CIVector(x: 0, y: 0, z: 1, w: -ciColor.blue) let alphaVector = CIVector(x: 0, y: 0, z: 0, w: 1) colorMatrixFilter.setValue(redVector, forKey: "inputRVector") colorMatrixFilter.setValue(greenVector, forKey: "inputGVector") colorMatrixFilter.setValue(blueVector, forKey: "inputBVector") colorMatrixFilter.setValue(alphaVector, forKey: "inputAVector") // 2. 模糊+阈值处理,生成平滑的透明度遮罩 let blurFilter = CIFilter(name: "CIGaussianBlur")! blurFilter.setValue(colorMatrixFilter.outputImage, forKey: kCIInputImageKey) blurFilter.setValue(tolerance * 10, forKey: kCIInputRadiusKey) let thresholdFilter = CIFilter(name: "CIColorThreshold")! thresholdFilter.setValue(blurFilter.outputImage, forKey: kCIInputImageKey) thresholdFilter.setValue(tolerance, forKey: kCIInputThresholdKey) // 3. 将遮罩转为Alpha通道,实现透明效果 let maskToAlphaFilter = CIFilter(name: "CIMaskToAlpha")! maskToAlphaFilter.setValue(thresholdFilter.outputImage, forKey: kCIInputImageKey) return maskToAlphaFilter }
2. 生成带透明效果的AVPlayerItem
对应你代码中的createTransparentItem函数,生成可直接播放的透明视频项:
func createTransparentItem(url: URL, targetColor: UIColor = .green) -> AVPlayerItem? { let asset = AVAsset(url: url) // 创建视频合成轨道 let composition = AVMutableComposition() guard let sourceVideoTrack = asset.tracks(withMediaType: .video).first else { return nil } let compositionVideoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)! do { try compositionVideoTrack.insertTimeRange(CMTimeRangeMake(start: .zero, duration: asset.duration), of: sourceVideoTrack, at: .zero) } catch { print("插入视频轨道失败: \(error)") return nil } // 配置视频帧处理逻辑 let videoComposition = AVMutableVideoComposition(asset: asset) { request in let sourceImage = request.sourceImage guard let filter = createColorKeyFilter(targetColor: targetColor) else { request.finish(with: sourceImage, context: nil) return } filter.setValue(sourceImage, forKey: kCIInputImageKey) guard let outputImage = filter.outputImage else { request.finish(with: sourceImage, context: nil) return } // 确保输出图像带Alpha通道 let context = CIContext(options: [.workingColorSpace: kCFNull!]) let cgImage = context.createCGImage(outputImage, from: outputImage.extent)! let finalImage = CIImage(cgImage: cgImage) request.finish(with: finalImage, context: nil) } // 设置合成属性,支持透明背景 videoComposition.renderSize = sourceVideoTrack.naturalSize videoComposition.frameDuration = sourceVideoTrack.minFrameDuration videoComposition.backgroundColor = UIColor.clear.cgColor let playerItem = AVPlayerItem(asset: composition) playerItem.videoComposition = videoComposition return playerItem }
3. 保存处理后的视频到本地
如果需要将透明视频导出保存,用AVAssetExportSession实现:
func exportTransparentVideo(from url: URL, targetColor: UIColor, outputURL: URL, completion: @escaping (Error?) -> Void) { guard let playerItem = createTransparentItem(url: url, targetColor: targetColor) else { completion(NSError(domain: "VideoProcessing", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法创建透明视频项"])) return } let asset = playerItem.asset // 选择支持Alpha通道的导出预设 guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHEVCWithAlpha) else { completion(NSError(domain: "VideoProcessing", code: -2, userInfo: [NSLocalizedDescriptionKey: "无法创建导出会话"])) return } exportSession.outputURL = outputURL exportSession.outputFileType = .mov // MOV格式原生支持Alpha通道 exportSession.videoComposition = playerItem.videoComposition exportSession.exportAsynchronously { if exportSession.status == .completed { completion(nil) } else { completion(exportSession.error) } } }
4. 适配你的原有代码
补充目标颜色参数,即可直接使用:
let player = AVPlayerView(frame: CGRect(origin: .zero, size: videoSize)) let url: URL = Bundle.main.url(forResource: "video", withExtension: "mp4")! // 指定要抠除的颜色,示例为绿色 let playerItem = createTransparentItem(url: url, targetColor: .green) player.loadPlayerItem(playerItem) { [weak self] result in switch result { case .failure(let error): print("加载失败", error) case .success(let player): player.play() self?.animateBackgroundColor() } }
关键注意事项
- 格式限制:只有MOV、ProRes等格式支持Alpha通道,导出时需选择对应格式和预设
- 容差调整:
tolerance值越大,越接近目标颜色的区域会被转为透明,可根据实际视频调整 - 性能优化:处理高分辨率视频时,建议将帧处理逻辑放在后台队列,避免阻塞主线程
内容的提问来源于stack exchange,提问作者CYAD
相关产品推荐
相关产品推荐

