3

我正在尝试在 iOS 上使用 openCV 3 从多次曝光中生成 HDR 图像,最终将输出为 EXR 文件。当我尝试创建 HDR 图像时,我注意到输出出现乱码。认为尝试创建相机响应是一个错误,我从头开始并将 openCV 上的 HDR 成像教程材料改编为 iOS,但它产生了类似的结果。以下 C++ 代码返回乱码图像:

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
}

这是图像的样子:

图像输出不良

我分析了图像,尝试了各种色彩空间转换,但数据似乎是垃圾。

openCV 框架是来自 openCV.org 网站的最新编译的 3.0.0 版本。RC 和 alpha 产生相同的结果,并且当前版本不会构建(对于 iOS 或 OSX)。我在想我的下一步是尝试让框架从头开始编译,或者让示例在另一个平台下工作,看看问题是特定于平台的还是与 openCV HDR 函数本身有关。但在我这样做之前,我想我会把这个问题放在堆栈溢出上,看看是否有人遇到过同样的问题,或者我是否遗漏了一些非常明显的东西。

我已将示例 xcode 项目上传到此处:

https://github.com/artandmath/openCVHDRSwiftExample

让 openCV 与 swift 一起工作是在 Github 上用户代工厂的帮助下

4

1 回答 1

2

感谢铸造厂为我指明了正确的方向。UIImage+OpenCV 类扩展期望每个颜色通道有 8 位,但是 HDR 函数会吐出每个通道 32 位(这实际上是我想要的)。在将图像矩阵转换为 UIImage 之前,将图像矩阵转换回每通道 8 位以用于显示目的可以解决此问题。

这是生成的图像:

预期的结果!

这是固定功能:

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;
    */
}

或者,这里是 OpenCV+UIImage 类扩展中的 initWithCVMat 方法的修复,基于 opencv.org 上 iOS 部分中的一个 iOS 教程:

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

在使用浮点数据创建新的 CGImageRef 时,需要明确告知它需要浮点数据,并且需要反转来自 openCV 的图像数据的字节顺序。现在 iOS/Quartz 有了浮点数据!这是一个 hacky 修复,因为该方法仍然只处理每个通道或 alpha 的 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;
}
于 2015-12-01T08:42:52.180 回答