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

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

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

Самый простой способ — использовать jpegStillImageNSDataRepresentation: from 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 МБ сразу после поляризации Бейера!


person thomketler    schedule 23.07.2012    source источник
comment
Я нашел этот ответ примерно за 10 секунд поиска: stackoverflow.com/a/10865206/96716   -  person David H    schedule 23.07.2012
comment
Спасибо, Дастин, я уже боялся чего-то подобного, я просто надеялся, что кто-то может мне подсказать или что-то в этом роде. И спасибо Дэвиду Х, но я уже просмотрел это, и это не очень помогает моему делу, или, по крайней мере, я не смог понять, как это сделать. Но я благодарен за каждый намек!   -  person thomketler    schedule 23.07.2012


Ответы (4)


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

person Brad Larson    schedule 23.07.2012
comment
Большое вам спасибо за вашу помощь. Приятно знать, что я не был на совершенно неправильном пути. Надеюсь, я не испытываю вашего терпения, но знаете ли вы простой способ превратить это в растровое изображение? Я думаю об использовании openCV аналогично тому, как это делается в другом сообщении link Я просто хочу знать, не пропустил ли я гораздо более простой способ. И еще раз спасибо, я уже некоторое время бьюсь об стену с этим. - person thomketler; 24.07.2012

Я мог бы решить это с помощью 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 МБ сразу после байеровского фильтра!

person thomketler    schedule 03.08.2012

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

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

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

person Wildaker    schedule 23.07.2012
comment
Одна вещь, о которой следует помнить: kCVPixelBufferPixelFormatTypeKey - это целое число, поэтому вам придется обернуть его в NSNumber при добавлении в ваш словарь. Кроме того, в ARC вам придется вручную привести фактическое значение к id. - person FeifanZ; 02.08.2012

как упоминал @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. Надеюсь, это поможет.

person G. Führ    schedule 13.01.2017