GPUI图像裁剪到CGRect并旋转



给定一个CGRect,我想使用GPUImage来裁剪视频。例如,如果rect是(0, 0, 50, 50),则视频将在(0,0)处被裁剪,每侧的长度为50。

让我感到困惑的是,GPUImageCropFilter不采用矩形,而是一个值从0到1的归一化裁剪区域。我的直觉是:

let assetSize = CGSizeApplyAffineTransform(videoTrack.naturalSize, videoTrack.preferredTransform)
let cropRect = CGRect(x: frame.minX/assetSize.width,
                y: frame.minY/assetSize.height,
                width: frame.width/assetSize.width,
                height: frame.height/assetSize.height)

以基于传入资产的大小来计算裁剪区域。然后:

// Filter
let cropFilter = GPUImageCropFilter(cropRegion: cropRect)
let url = NSURL(fileURLWithPath: "(NSTemporaryDirectory())(String.random()).mp4")
let movieWriter = GPUImageMovieWriter(movieURL: url, size: assetSize)
movieWriter.encodingLiveVideo = false
movieWriter.shouldPassthroughAudio = false
// add targets
movieFile.addTarget(cropFilter)
cropFilter.addTarget(movieWriter)
cropFilter.forceProcessingAtSize(frame.size)
cropFilter.setInputRotation(kGPUImageRotateRight, atIndex: 0)

电影编剧的尺寸应该是多少?它不应该是我想要裁剪的框架的大小吗?我应该将forceProcessingAtSize与裁剪框的大小值一起使用吗?

一个完整的代码示例会很好;我已经试了好几个小时了,但似乎找不到我想要的视频部分。

最终:

if let videoTrack = self.asset.tracks.first {
            let movieFile = GPUImageMovie(asset: self.asset)
            let transformedRegion = CGRectApplyAffineTransform(region, videoTrack.preferredTransform)
            // Filters
            let cropFilter = GPUImageCropFilter(cropRegion: transformedRegion)
            let url = NSURL(fileURLWithPath: "(NSTemporaryDirectory())(String.random()).mp4")
            let renderSize = CGSizeApplyAffineTransform(videoTrack.naturalSize, CGAffineTransformMakeScale(transformedRegion.width, transformedRegion.height))
            let movieWriter = GPUImageMovieWriter(movieURL: url, size: renderSize)
            movieWriter.transform = videoTrack.preferredTransform
            movieWriter.encodingLiveVideo = false
            movieWriter.shouldPassthroughAudio = false
            // add targets
            // http://stackoverflow.com/questions/37041231/gpuimage-crop-to-cgrect-and-rotate
            movieFile.addTarget(cropFilter)
            cropFilter.addTarget(movieWriter)
            movieWriter.completionBlock = {
                observer.sendNext(url)
                observer.sendCompleted()
            }
            movieWriter.failureBlock = { _ in
                observer.sendFailed(.VideoCropFailed)
            }
            disposable.addDisposable {
                cropFilter.removeTarget(movieWriter)
                movieWriter.finishRecording()
            }
            movieWriter.startRecording()
            movieFile.startProcessing()
        }

正如您所注意到的,GPUImageCropFilter采用标准化坐标中的矩形。你走在了正确的轨道上,因为你只需要通过将X分量(origin.X和size.width)除以图像的宽度,将Y分量除以高度,将以像素为单位的CGRect转换为标准化坐标。

您不需要使用forceProcessingAtSize(),因为裁剪会自动输出适当裁剪大小的图像。电影编剧的尺寸应该与这个裁剪的尺寸相匹配,你应该从你的原始CGRect中知道。

你介绍的一个复杂情况是轮换。如果除了作物外还需要应用旋转,您可能需要检查并确保不需要将X和Y替换为作物区域。如果两者需要交换,那么这一点在输出中应该很明显。

前一段时间,在作物同时应用轮作时出现了一些错误,我不记得我是否修复了所有这些错误。如果我没有,你可以在裁剪之前或之后插入一个伪过滤器(gamma或亮度设置为默认值),并在那个阶段应用旋转。

最新更新