Необработанные данные изображения с камеры, такие как "645 PRO"

Некоторое время назад я уже задавал этот вопрос, и я также получил хороший ответ:

Я искал этот форум вверх и вниз, но я не мог найти то, что мне действительно нужно. Я хочу получить необработанные данные изображения с камеры. До сих пор я пытался извлечь данные из imageDataSampleBuffer из этого метода captureStillImageAsynchronouslyFromConnection: завершению Handler: и записать их в объект NSData, но это не сработало. Может быть, я не на том пути или, может быть, я делаю это неправильно. Я не хочу, чтобы изображение было сжато каким-либо образом.

Самый простой способ - использовать jpegStillImageNSDataRepresentation: из AVCaptureStillImageOutput, но, как я уже сказал, я не хочу, чтобы он был сжат.

Спасибо!

Необработанные данные изображения с камеры

Я думал, что смогу с этим поработать, но наконец-то заметил, что мне нужно получать необработанные данные изображения более прямым образом, как это делается в "645 PRO".

645 PRO: RAW Redux

Изображения на этом сайте показывают, что они получают необработанные данные до того, как будет выполнено любое сжатие JPEG. Это то, что я хочу сделать. Я думаю, что мне нужно преобразовать imageDataSampleBuffer но я не вижу способа сделать это полностью без сжатия. "645 PRO" также сохраняет свои изображения в формате TIFF, поэтому я думаю, что он использует по крайней мере одну дополнительную библиотеку.

Я не хочу делать приложение для фотографий, но мне нужно лучшее качество, которое я получаю, чтобы проверить определенные функции на фотографии.

Спасибо!

Редактировать 1: Итак, после попыток и поиска в разных направлениях некоторое время, я решил обновить статус.

Конечная цель этого проекта - проверить наличие определенных функций на картинке, что произойдет с помощью opencv. Но до тех пор, пока приложение не сможет сделать это на телефоне, я пытаюсь вытащить в основном несжатые картинки из телефона, чтобы проанализировать их на компьютере.

Поэтому я хочу сохранить "экземпляр NSData, содержащий несжатые байты BGRA, возвращенные с камеры", которые я могу получить с кодом Брэда Ларсона в виде файла 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или же 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);

Мне просто нужно использовать функцию imwrite из opencv. Таким образом, я получаю TIFF-файлы размером около 30 МБ непосредственно после поляризации beyer!

4 ответа

Решение

Я мог бы решить это с 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);

Мне просто нужно использовать функцию imwrite из opencv. Таким образом, я получаю BMP-файлы размером около 24 МБ сразу после байер-фильтра!

Вау, этот пост был чем-то особенным. Множество слов, чтобы просто заявить, что они получают образцы буферных байтов, которые 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 и просто работал с байтовым массивом из пиксельного буфера.

В то время как ядром ответа является Брэд из iOS: получать попиксельные данные с камеры, из ответа Брэда совершенно неясен ключевой элемент. Он скрыт в "как только вы настроили свой сеанс захвата...".

Вам нужно установить правильные выходные параметры для вашего AVCaptureStillImageOutput,

Например, настройка kCVPixelBufferPixelFormatTypeKey в kCVPixelFormatType_420YpCbCr8BiPlanarFullRange даст вам YCbCr imageDataSampleBuffer в captureStillImageAsynchronouslyFromConnection:completionHandler:, который вы можете затем манипулировать по своему усмотрению.

Как упомянул @Wildaker, для того, чтобы конкретный код работал, вы должны быть уверены, какой формат пикселя посылает вам камера. Код из @thomketler будет работать, если он установлен для 32-битного формата RGBA.

Вот код для YUV по умолчанию с камеры, используя OpenCV:

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. Надеюсь, это поможет.

Другие вопросы по тегам