You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不损失画质的情况下调整UIImage尺寸?(ARKit场景)

CVPixelBuffer转UIImage:解决画质损失与比例失调问题

你的核心问题出在先缩放到归一化尺寸再放大的流程——这会丢失大量像素信息,导致画质模糊;而调整缩放逻辑时没处理好等比适配,才会出现裁切或比例失调。

直接在原始像素分辨率上处理变换,再做等比缩放是最优解,以下是可直接复用的代码方案:

import ARKit
import UIKit

extension UIImage {
    static func from(pixelBuffer: CVPixelBuffer, frame: ARFrame, targetSize: CGSize) -> UIImage? {
        // 获取CVPixelBuffer原始分辨率
        let pixelWidth = CVPixelBufferGetWidth(pixelBuffer)
        let pixelHeight = CVPixelBufferGetHeight(pixelBuffer)
        let originalPixelSize = CGSize(width: pixelWidth, height: pixelHeight)
        
        // 基于原始像素尺寸获取displayTransform,避免先缩后放
        let orientation: UIInterfaceOrientation = .portrait // 根据你的界面方向调整
        let transform = frame.displayTransform(for: orientation, viewportSize: originalPixelSize)
        
        // 将CVPixelBuffer转为CGImage
        guard let cgImage = CGImage.create(from: pixelBuffer) else { return nil }
        
        // 应用方向变换到高分辨率图像上
        guard let context = CGContext(data: nil,
                                      width: pixelWidth,
                                      height: pixelHeight,
                                      bitsPerComponent: cgImage.bitsPerComponent,
                                      bytesPerRow: cgImage.bytesPerRow,
                                      space: cgImage.colorSpace!,
                                      bitmapInfo: cgImage.bitmapInfo.rawValue) else { return nil }
        context.concatenate(transform)
        guard let transformedCGImage = context.makeImage() else { return nil }
        
        // 等比缩放到目标尺寸,保证完整显示不裁切
        let scaleFactor = min(targetSize.width / originalPixelSize.width, targetSize.height / originalPixelSize.height)
        let scaledSize = CGSize(width: originalPixelSize.width * scaleFactor,
                                height: originalPixelSize.height * scaleFactor)
        
        UIGraphicsBeginImageContextWithOptions(scaledSize, false, UIScreen.main.scale)
        transformedCGImage.draw(in: CGRect(origin: .zero, size: scaledSize))
        let finalImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return finalImage
    }
}

extension CGImage {
    static func create(from pixelBuffer: CVPixelBuffer) -> CGImage? {
        let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
        // 用硬件加速的CIContext提升转换性能
        let context = CIContext(options: [.useSoftwareRenderer: false])
        return context.createCGImage(ciImage, from: ciImage.extent)
    }
}

关键细节说明

  1. 避免先缩后放:调用displayTransform时传入CVPixelBuffer的原始像素尺寸作为viewportSize,让ARKit直接在高分辨率图像上计算方向变换,彻底解决画质损失问题。
  2. 等比适配防止裁切:缩放时取目标视图宽高比与原始图像宽高比的最小值作为缩放因子,保证图像完整显示,不会出现裁切或拉伸变形。
  3. 适配屏幕分辨率:用UIScreen.main.scale创建绘图上下文,确保缩放后的图像在不同分辨率设备上显示清晰。

调整方向适配

如果你的界面支持横竖屏切换,只需修改orientation参数为当前的UIInterfaceOrientation即可,比如:

let orientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation ?? .portrait

内容的提问来源于stack exchange,提问作者Kevvv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 13:10:25