来自相机的原始图像数据,如“645 PRO”

时间:2012-07-23 12:34:30

标签: ios image opencv camera imagemagick

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

  

我一直在搜索这个论坛,但我找不到我的意思   真的需要。我想从相机获取原始图像数据。至目前为止   我试图从中获取dataDataSampleBuffer中的数据   方法   captureStillImageAsynchronouslyFromConnection:completionHandler:和   将它写入NSData对象,但这不起作用。也许我在   错误的轨道或者我只是做错了。我不想要的是   用于以任何方式压缩图像。

     

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

     

谢谢!

Raw image data from camera

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

645 PRO: RAW Redux

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

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

谢谢!

编辑1: 因此,在尝试并在不同方向上搜索一段时间之后,我决定进行状态更新。

这个项目的最终目标是检查图片中的某些功能,这些功能将在opencv的帮助下发生。但是,直到该应用程序能够在手机上进行,我试图从手机中获取大部分未压缩的图片,以便在计算机上进行分析。

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

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 - 方法

我尝试的另一件事是使用another post中建议的ImageMagick。 但是,如果不使用UIImagePNGRepresentationUIImageJPEGRepresentation之类的内容,我无法找到方法。

现在我正在尝试使用此tutorial与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-Polarization之后直接获得大约30 MB的TIFF文件!

4 个答案:

答案 0 :(得分:16)

哇,这篇博文很特别。很多单词只是声明他们得到了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创建的开销,只使用像素缓冲区中的字节数组。

答案 1 :(得分: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文件!

答案 2 :(得分:2)

虽然答案的核心来自布拉德iOS: Get pixel-by-pixel data from camera,但布拉德回答中的一个关键因素尚不清楚。一旦您配置了捕获会话,它就隐藏在""。

您需要为AVCaptureStillImageOutput设置正确的outputSettings。

例如,将kCVPixelBufferPixelFormatTypeKey设置为kCVPixelFormatType_420YpCbCr8BiPlanarFullRange会在imageDataSampleBuffer中为您提供YCbCr captureStillImageAsynchronouslyFromConnection:completionHandler:,然后您可以根据自己的内容进行操作。< / p>

答案 3 :(得分:0)

正如@Wildaker所提到的,要使用特定代码,您必须确定相机正在向您发送哪种像素格式。如果将@thomketler的代码设置为32位RGBA格式,则该代码将起作用。

以下是使用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帧。我希望有所帮助。