使用 vImageScale_ARGB8888 缩放图像时图像质量受到影响 - Cocoa Objective C

Posted

技术标签:

【中文标题】使用 vImageScale_ARGB8888 缩放图像时图像质量受到影响 - Cocoa Objective C【英文标题】:Image Quality getting affected on scaling the image using vImageScale_ARGB8888 - Cocoa Objective C 【发布时间】:2020-08-01 12:58:37 【问题描述】:

我正在使用AVCaptureSession 捕获我的系统屏幕,然后从捕获的图像缓冲区中创建一个视频文件。它工作正常。

现在我想通过保持视频文件尺寸的纵横比来缩放图像缓冲区。我使用以下代码来缩放图像。

- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 

    CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    
    if (pixelBuffer == NULL)  return; 
    
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    
    size_t finalWidth = 1080;
    size_t finalHeight = 720;
    
    size_t sourceWidth = CVPixelBufferGetWidth(imageBuffer);
    size_t sourceHeight = CVPixelBufferGetHeight(imageBuffer);
    
    CGRect aspectRect = AVMakeRectWithAspectRatioInsideRect(CGSizeMake(sourceWidth, sourceHeight), CGRectMake(0, 0, finalWidth, finalHeight));
    
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);

    size_t startY = aspectRect.origin.y;
    size_t yOffSet = (finalWidth*startY*4);
    CVPixelBufferLockBaseAddress(imageBuffer, 0);
    
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
    
    void* destData = malloc(finalHeight * finalWidth * 4);
    
    vImage_Buffer srcBuffer =  (void *)baseAddress, sourceHeight, sourceWidth, bytesPerRow;
    vImage_Buffer destBuffer =  (void *)destData+yOffSet, aspectRect.size.height, aspectRect.size.width, aspectRect.size.width * 4;
    
    vImage_Error err = vImageScale_ARGB8888(&srcBuffer, &destBuffer, NULL, 0);
    
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    OSType pixelFormat = CVPixelBufferGetPixelFormatType(imageBuffer);
    
    CVImageBufferRef pixelBuffer1 = NULL;
    
    CVReturn result = CVPixelBufferCreateWithBytes(NULL, finalWidth, finalHeight, pixelFormat, destData, finalWidth * 4, NULL, NULL, NULL, &pixelBuffer1);

我可以使用上述代码缩放图像,但与使用预览应用程序调整图像大小相比,最终图像似乎模糊。因此视频不清楚。

如果我使用以下代码将输出像素格式更改为 RGB,这将正常工作。

output.videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey, nil];

但我想要 YUV 格式的图像缓冲区(这是 AVCaptureVideoDataOutput 的默认格式),因为这会在通过网络传输时减小缓冲区的大小。

缩放后的图像:

使用预览应用调整图像大小:

我尝试使用 vImageScale_CbCr8 代替 vImageScale_ARGB8888,但生成的图像不包含正确的 RGB 值。

我也注意到有转换图像格式的功能:vImageConvert_422YpCbYpCr8ToARGB8888(const vImage_Buffer *src, const vImage_Buffer *dest, const vImage_YpCbCrToARGB *info, const uint8_t permuteMap[4], const uint8_t alpha, vImage_Flags flags);

但我不知道 vImage_YpCbCrToARGB 和 permuteMap 的值应该是什么,因为我对图像处理一无所知。

预期解决方案:

如何将 YUV 像素缓冲区转换为 RGB 缓冲区并返回到 YUV(或)如何在不影响 RGB 值的情况下缩放 YUV 像素缓冲区。

【问题讨论】:

@OlSen 我发现CVImageBufferRef 返回的表单AVCaptureVideoDataOutputSampleBufferDelegatekCVPixelFormatType_422YpCbCr8 格式。如果我将AVCaptureVideoDataOutput 的videoSettings 像素格式设置为kCVPixelFormatType_32BGRA,则缩放效果完美。但我想以422YpCbCr8 格式维护缓冲区,因为我将通过网络发送这些数据。 @OlSen 更新了我的问题。我希望这很清楚。 【参考方案1】:

经过大量搜索和处理与图像渲染相关的不同问题,找到以下代码来转换图像缓冲区的像素格式。感谢this链接中的答案。

CVPixelBufferRef imageBuffer;
CVPixelBufferCreate(kCFAllocatorDefault, sourceWidth, sourceHeight, kCVPixelFormatType_32ARGB, 0, &imageBuffer);

VTPixelTransferSessionTransferImage(pixelTransferSession, pixelBuffer, imageBuffer);

【讨论】:

以上是关于使用 vImageScale_ARGB8888 缩放图像时图像质量受到影响 - Cocoa Objective C的主要内容,如果未能解决你的问题,请参考以下文章

复合服务器 8888 失败并显示“无法连接到 [localhost:27017]”

宝塔面板修改默认的放行端口8888为8001并且生效

Android ARGB_8888 转 RGB

LVM根分区缩容

mamp pro 虚拟主机只能在 8888 端口上工作

如何使用 postcss 在顺风中压缩文件大小?