Необработанные данные изображения с камеры, такие как "645 PRO"
Некоторое время назад я уже задавал этот вопрос, и я также получил хороший ответ:
Я искал этот форум вверх и вниз, но я не мог найти то, что мне действительно нужно. Я хочу получить необработанные данные изображения с камеры. До сих пор я пытался извлечь данные из imageDataSampleBuffer из этого метода captureStillImageAsynchronouslyFromConnection: завершению Handler: и записать их в объект NSData, но это не сработало. Может быть, я не на том пути или, может быть, я делаю это неправильно. Я не хочу, чтобы изображение было сжато каким-либо образом.
Самый простой способ - использовать jpegStillImageNSDataRepresentation: из AVCaptureStillImageOutput, но, как я уже сказал, я не хочу, чтобы он был сжат.
Спасибо!
Необработанные данные изображения с камеры
Я думал, что смогу с этим поработать, но наконец-то заметил, что мне нужно получать необработанные данные изображения более прямым образом, как это делается в "645 PRO".
Изображения на этом сайте показывают, что они получают необработанные данные до того, как будет выполнено любое сжатие 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. Надеюсь, это поможет.