使用 vImageScale_ARGB8888 - Cocoa Objective C 缩放图像会影响图像质量
Image Quality getting affected on scaling the image using vImageScale_ARGB8888 - Cocoa Objective C
我正在使用 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 像素缓冲区。
经过大量搜索并解决了与图像渲染相关的不同问题后,找到了以下代码来转换图像缓冲区的像素格式。感谢 link.
中的回答
CVPixelBufferRef imageBuffer;
CVPixelBufferCreate(kCFAllocatorDefault, sourceWidth, sourceHeight, kCVPixelFormatType_32ARGB, 0, &imageBuffer);
VTPixelTransferSessionTransferImage(pixelTransferSession, pixelBuffer, imageBuffer);
我正在使用 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 像素缓冲区。
经过大量搜索并解决了与图像渲染相关的不同问题后,找到了以下代码来转换图像缓冲区的像素格式。感谢
CVPixelBufferRef imageBuffer;
CVPixelBufferCreate(kCFAllocatorDefault, sourceWidth, sourceHeight, kCVPixelFormatType_32ARGB, 0, &imageBuffer);
VTPixelTransferSessionTransferImage(pixelTransferSession, pixelBuffer, imageBuffer);