2015-12-01 1 views
3

Я пытаюсь использовать openCV 3 на iOS для создания HDR-изображения из нескольких экспозиций, которые в конечном итоге будут выводиться как EXR-файл. Я заметил, что получаю искаженный вывод, когда пытался создать HDR-образ. Думая, что это была ошибка при попытке создать ответ камеры, я начал с нуля и адаптировал материал для создания изображений HDR на openCV для iOS, но он дает похожие результаты. Следующий C++ код возвращает искаженное изображение:Изображение с высоким динамическим диапазоном с использованием openCV на iOS производит искаженный вывод

cv::Mat mergeToHDR (vector<Mat>& images, vector<float>& times) 
{ 
    imgs = images; 
    Mat response; 
    //Ptr<CalibrateDebevec> calibrate = createCalibrateDebevec(); 
    //calibrate->process(images, response, times); 

    Ptr<CalibrateRobertson> calibrate = createCalibrateRobertson(); 
    calibrate->process(images, response, times); 

    // create HDR 
    Mat hdr; 
    Ptr<MergeDebevec> merge_debevec = createMergeDebevec(); 
    merge_debevec->process(images, hdr, times, response); 

    // create LDR 
    Mat ldr; 
    Ptr<TonemapDurand> tonemap = createTonemapDurand(2.2f); 
    tonemap->process(hdr, ldr); 

    // create fusion 
    Mat fusion; 
    Ptr<MergeMertens> merge_mertens = createMergeMertens(); 
    merge_mertens->process(images, fusion); 

    /* 
    Uncomment what kind of tonemapped image or hdr to return 
    Returning one of the images in the array produces ungarbled output 
    so we know the problem is unlikely with the openCV to UIImage conversion 
    */ 

    //give back one of the images from the image array 
    //return images[0]; 

    //give back one of the hdr images 
    return fusion * 255; 
    //return ldr * 255; 
    //return hdr 
} 

Это то, что изображение выглядит следующим образом:

Bad image output

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

Основой openCV является последняя скомпилированная версия 3.0.0 с сайта openCV.org. RC и alpha дают одинаковые результаты, а текущая версия не будет построена (для iOS или OSX). Я думал, что мои последующие шаги состоят в том, чтобы попытаться скомпилировать фреймворк с нуля или получить пример, работающий под другой платформой, чтобы узнать, является ли проблема специфичной для платформы или с самими функциями OpenCV HDR. Но прежде чем я это сделаю, я подумал, что я бы бросил проблему на переполнение стека, чтобы увидеть, столкнулся ли кто-нибудь с одной и той же проблемой, или если я пропущу что-то ослепительно очевидное.

Я загрузил Xcode проект примера сюда:

https://github.com/artandmath/openCVHDRSwiftExample

Получения OpenCV для работы с быстрым был с помощью пользовательских литейного на Github

+0

Я могу подтвердить, что образец кода отлично работает под OSX, в то время как ваша версия проекта не отключает iOS. Это немного сужает проблему. – foundry

+0

исправление для комментариев - код работает одинаково на OSX, но с помощью imshow() форматы преобразования корректно.На iOS, проходящем через оболочку, есть проблема с преобразованием формата ... – foundry

+0

Спасибо @foundry. Я восстановил структуру, чтобы быть уверенным, и столкнулся с той же проблемой. Снова перейдя через UIImage + OpenCV, initWithCVMat ожидает жестко закодированный 8-битный канал на пиксель, поэтому я думаю, что проблема может быть исправлена ​​здесь, или я могу преобразовать изображение в 8-бит в openCV, прежде чем передать его UIKit. – Artandmath

ответ

2

Благодаря литейные указала мне в праве направление. Расширение класса UIImage + OpenCV ожидает 8 бит на цветной канал, однако функции HDR выплевывают 32 бита на канал (что на самом деле я хочу). Преобразование матрицы изображения обратно в 8 бит на канал для целей отображения до преобразования его в UIImage устраняет проблему.

Вот результирующее изображение:

The expected result!

Вот фиксированная функция:

cv::Mat mergeToHDR (vector<Mat>& images, vector<float>& times) 
{ 
    imgs = images; 
    Mat response; 
    //Ptr<CalibrateDebevec> calibrate = createCalibrateDebevec(); 
    //calibrate->process(images, response, times); 

    Ptr<CalibrateRobertson> calibrate = createCalibrateRobertson(); 
    calibrate->process(images, response, times); 

    // create HDR 
    Mat hdr; 
    Ptr<MergeDebevec> merge_debevec = createMergeDebevec(); 
    merge_debevec->process(images, hdr, times, response); 

    // create LDR 
    Mat ldr; 
    Ptr<TonemapDurand> tonemap = createTonemapDurand(2.2f); 
    tonemap->process(hdr, ldr); 

    // create fusion 
    Mat fusion; 
    Ptr<MergeMertens> merge_mertens = createMergeMertens(); 
    merge_mertens->process(images, fusion); 

    /* 
    Uncomment what kind of tonemapped image or hdr to return 
    Convert back to 8-bits per channel because that is what 
    the UIImage+OpenCV class extension is expecting 
    */ 


    // tone mapped 
    /* 
    Mat ldr8bit; 
    ldr = ldr * 255; 
    ldr.convertTo(ldr8bit, CV_8U); 
    return ldr8bit; 
    */ 

    // fusion 
    Mat fusion8bit; 
    fusion = fusion * 255; 
    fusion.convertTo(fusion8bit, CV_8U); 
    return fusion8bit; 

    // hdr 
    /* 
    Mat hdr8bit; 
    hdr = hdr * 255; 
    hdr.convertTo(hdr8bit, CV_8U); 
    return hdr8bit; 
    */ 
} 

В качестве альтернативы здесь фикс для метода initWithCVMat в расширении класса OpenCV + UIImage на основе один из руководств iOS в разделе iOS на opencv.org:

http://docs.opencv.org/2.4/doc/tutorials/ios/image_manipulation/image_manipulation.html#opencviosimagemanipulation

При создании нового CGImageRef с данными с плавающей запятой необходимо явно указать, что он ожидает данные с плавающей запятой, и порядок байтов данных изображения из openCV должен быть отменен. Теперь iOS/Quartz имеет данные по плаванию! Это немного хакерское исправление, потому что метод по-прежнему касается только 8 бит или 32 бит на канал или альфа и не учитывает все виды изображений, которые могут быть переданы от Mat к UIImage.

- (id)initWithCVMat:(const cv::Mat&)cvMat 
{ 
    NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()]; 
    CGColorSpaceRef colorSpace; 

    size_t elemSize = cvMat.elemSize(); 
    size_t elemSize1 = cvMat.elemSize1(); 

    size_t channelCount = elemSize/elemSize1; 
    size_t bitsPerChannel = 8 * elemSize1; 
    size_t bitsPerPixel = bitsPerChannel * channelCount; 

    if (channelCount == 1) { 
     colorSpace = CGColorSpaceCreateDeviceGray(); 
    } else { 
     colorSpace = CGColorSpaceCreateDeviceRGB(); 
    } 

    // Tell CGIImageRef different bitmap info if handed 32-bit 
    uint32_t bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault; 

    if (bitsPerChannel == 32){ 
     bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapFloatComponents | kCGBitmapByteOrder32Little; 
    } 

    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); 

    // Creating CGImage from cv::Mat 
    CGImageRef imageRef = CGImageCreate(cvMat.cols,         //width 
             cvMat.rows,         //height 
             bitsPerChannel,        //bits per component 
             bitsPerPixel,        //bits per pixel 
             cvMat.step[0],        //bytesPerRow 
             colorSpace,         //colorspace 
             bitmapInfo,         // bitmap info 
             provider,         //CGDataProviderRef 
             NULL,          //decode 
             false,          //should interpolate 
             kCGRenderingIntentDefault     //intent 
             );      

    // Getting UIImage from CGImage 
    self = [self initWithCGImage:imageRef]; 
    CGImageRelease(imageRef); 
    CGDataProviderRelease(provider); 
    CGColorSpaceRelease(colorSpace); 

    return self; 
} 
+0

Сколько изображений вы захватили, и время - это время захвата каждого изображения. Это? – Abc