12

前段时间我已经问过这个问题,我也得到了一个很好的答案:

我一直在搜索这个论坛,但我找不到我真正需要的东西。我想从相机获取原始图像数据。到目前为止,我试图从该方法 captureStillImageAsynchronouslyFromConnection:completionHandler: 中获取 imageDataSampleBuffer 中的数据并将其写入 NSData 对象,但这不起作用。也许我走错了路,或者我只是做错了。我不想要以任何方式压缩图像。

简单的方法是使用来自 AVCaptureStillImageOutput 的 jpegStillImageNSDataRepresentation:,但就像我说的那样,我不希望它被压缩。

谢谢!

来自相机的原始图像数据

我以为我可以使用它,但我终于注意到我需要以与“645 PRO”类似的方式更直接地获取原始图像数据。

645 PRO:原始还原

该网站上的图片显示他们在任何 jpeg 压缩完成之前获得了原始数据。这就是我想做的。我的猜测是我需要进行转换imageDataSampleBuffer,但我没有看到完全不压缩的方法。“645 PRO”还将其图片保存在 TIFF 中,因此我认为它至少使用了一个额外的库。

我不想制作照片应用程序,但我需要最好的质量来检查图片中的某些功能。

谢谢!

编辑1: 所以在尝试和搜索不同方向一段时间后,我决定更新状态。

该项目的最终目标是检查图片中的某些特征,这将在 opencv 的帮助下发生。但在应用程序能够在手机上执行此操作之前,我会尝试从手机中获取大部分未压缩的图片,以便在计算机上对其进行分析。

因此,我想保存“包含从相机返回的未压缩 BGRA 字节的 NSData 实例”,我可以使用 Brad Larson 的代码将其保存为 bmp 或 TIFF 文件。正如我在评论中所说,我尝试为此使用 opencv(无论如何都需要它)。但我能做的最好的事情就是把它变成一个 UIImage ,它具有来自Computer Vision Talks的功能。

void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
cv::Mat frame(height, width, CV_8UC4, (void*)baseAddress);
UIImage *testImag = [UIImage imageWithMat:frame andImageOrientation:UIImageOrientationUp];
//imageWithMat... being the function from Computer Vision Talks which I can post if someone wants to see it

ImageMagick - 方法

我尝试的另一件事是按照另一篇文章中的建议使用 ImageMagick 。UIImagePNGRepresentation但是如果不使用类似or的东西,我找不到办法做到这一点UIImageJPEGRepresentation

现在我正在尝试使用本教程对 libtiff 做一些事情。

也许有人有想法或知道将我的缓冲区对象转换为未压缩图片的更简单方法。再次提前感谢!

编辑2:

我发现了一些东西!我必须说我非常盲目。

void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
cv::Mat frame(height, width, CV_8UC4, (void*)baseAddress);

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"ocv%d.TIFF", picNum]];
const char* cPath = [filePath cStringUsingEncoding:NSMacOSRomanStringEncoding];

const cv::string newPaths = (const cv::string)cPath;

cv::imwrite(newPaths, frame);

我只需要使用 opencv 中的 imwrite 函数。通过这种方式,我在 beyer-Polarisation 之后直接获得了大约 30 MB 的 TIFF 文件!

4

4 回答 4

17

哇,那篇博文很特别。很多话只是说他们从静止图像中获得了 Apple 交给你的样本缓冲区字节。他们的方法没有什么特别创新的地方,我知道有很多相机应用程序可以做到这一点。

您可以使用如下代码获取从使用 AVCaptureStillImageOutput 拍摄的照片返回的原始字节:

[photoOutput captureStillImageAsynchronouslyFromConnection:[[photoOutput connections] objectAtIndex:0] completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
    CVImageBufferRef cameraFrame = CMSampleBufferGetImageBuffer(imageSampleBuffer);
    CVPixelBufferLockBaseAddress(cameraFrame, 0);
    GLubyte *rawImageBytes = CVPixelBufferGetBaseAddress(cameraFrame);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(cameraFrame);
    NSData *dataForRawBytes = [NSData dataWithBytes:rawImageBytes length:bytesPerRow * CVPixelBufferGetHeight(cameraFrame)];
    // Do whatever with your bytes

    CVPixelBufferUnlockBaseAddress(cameraFrame, 0);
}];

这将为您提供一个 NSData 实例,其中包含从相机返回的未压缩 BGRA 字节。您可以将它们保存到磁盘或对它们做任何您想做的事情。如果你真的需要自己处理字节,我会避免创建 NSData 的开销,只使用像素缓冲区中的字节数组。

于 2012-07-23T15:19:15.270 回答
5

我可以用 OpenCV 解决它。感谢所有帮助过我的人。

void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
cv::Mat frame(height, width, CV_8UC4, (void*)baseAddress);

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"ocv%d.BMP", picNum]];
const char* cPath = [filePath cStringUsingEncoding:NSMacOSRomanStringEncoding];

const cv::string newPaths = (const cv::string)cPath;

cv::imwrite(newPaths, frame);

我只需要使用 opencv 中的 imwrite 函数。这样我就可以在拜耳过滤器之后直接获得大约 24 MB 的 BMP 文件!

于 2012-08-03T12:43:51.850 回答
2

虽然答案的核心来自iOS 的 Brad:Get pixel-by-pixel data from camera,但 Brad 的回复中完全不清楚一个关键要素。它隐藏在“一旦您配置了捕获会话......”。

您需要为您的AVCaptureStillImageOutput.

例如,设置kCVPixelBufferPixelFormatTypeKeykCVPixelFormatType_420YpCbCr8BiPlanarFullRange会给你一个 YCbCr imageDataSampleBufferin captureStillImageAsynchronouslyFromConnection:completionHandler:,然后你可以随意操作它。

于 2012-07-23T15:37:18.393 回答
0

正如@Wildaker 提到的,要使特定代码起作用,您必须确定相机发送给您的像素格式。如果设置为 32 位 RGBA 格式,来自@thomketler 的代码将起作用。

这是使用 OpenCV 的相机默认 YUV 代码:

cv::Mat convertImage(CMSampleBufferRef sampleBuffer)
{
    CVImageBufferRef cameraFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(cameraFrame, 0);

    int w = (int)CVPixelBufferGetWidth(cameraFrame);
    int h = (int)CVPixelBufferGetHeight(cameraFrame);
    void *baseAddress = CVPixelBufferGetBaseAddressOfPlane(cameraFrame, 0);

    cv::Mat img_buffer(h+h/2, w, CV_8UC1, (uchar *)baseAddress);
    cv::Mat cam_frame;
    cv::cvtColor(img_buffer, cam_frame, cv::COLOR_YUV2BGR_NV21);
    cam_frame = cam_frame.t();

    //End processing
    CVPixelBufferUnlockBaseAddress( cameraFrame, 0 );

    return cam_frame;
}

cam_frame应该有完整的 BGR 框架。我希望这会有所帮助。

于 2017-01-13T19:42:20.660 回答