在iOS上使用openCV进行高动态范围成像会产生乱码输出
我正试图在iOS上使用openCV 3从多次曝光中生成HDR图像,最终输出为EXR文件。当我试图创建HDR图像时,我注意到我的输出被篡改了。我认为尝试创建相机响应是一个错误,于是从零开始,将openCV上的HDR成像教程材料改编为iOS,但它产生了类似的结果。下面的C++代码返回一个混乱的图像:在iOS上使用openCV进行高动态范围成像会产生乱码输出,ios,swift,opencv,hdr,Ios,Swift,Opencv,Hdr,我正试图在iOS上使用openCV 3从多次曝光中生成HDR图像,最终输出为EXR文件。当我试图创建HDR图像时,我注意到我的输出被篡改了。我认为尝试创建相机响应是一个错误,于是从零开始,将openCV上的HDR成像教程材料改编为iOS,但它产生了类似的结果。下面的C++代码返回一个混乱的图像: cv::Mat mergeToHDR (vector<Mat>& images, vector<float>& times) { imgs = image
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
}
cv::Mat mergeToHDR(向量和图像、向量和时间)
{
imgs=图像;
Mat响应;
//Ptr calibrate=createCalibrateDebevec();
//校准->过程(图像、响应、时间);
Ptr calibrate=createCalibrateRobertson();
校准->过程(图像、响应、时间);
//创建HDR
Mat-hdr;
Ptr merge_debevec=createMergeDebevec();
merge_debevec->process(图像、hdr、时间、响应);
//创建LDR
Mat-ldr;
Ptr tonemap=createTonemapDurand(2.2f);
音调映射->过程(hdr、ldr);
//创造融合
席状融合;
Ptr merge_mertens=createMergeMertens();
合并->处理(图像、融合);
/*
取消注释要返回的色调映射图像或hdr的类型
返回数组中的一个图像将生成未仲裁的输出
因此,我们知道openCV到UIImage转换不太可能出现问题
*/
//从图像阵列中返回一个图像
//返回图像[0];
//返回一个hdr图像
返回融合*255;
//返回ldr*255;
//返回hdr
}
这是图像的外观:
我分析了图像,尝试了各种颜色空间转换,但数据似乎是垃圾
openCV框架是openCV.org网站上最新编译的3.0.0版本。RC和alpha产生相同的结果,并且当前版本不会生成(对于iOS或OSX)。我想我的下一步将是尝试让框架从头开始编译,或者让示例在另一个平台下工作,看看问题是平台特定的还是openCV HDR函数本身。但在我这么做之前,我想我会在堆栈溢出上抛出这个问题,看看是否有人遇到过同样的问题,或者我是否遗漏了一些显而易见的东西
我已将示例xcode项目上载到此处:
让openCV与swift协同工作需要Github上用户foundry的帮助感谢foundry为我指明了正确的方向。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;
*/
}
我可以确认示例代码在OSX下运行良好,而您的项目版本没有卸载iOS。这将问题缩小了一点。对前面注释的更正-代码在OSX上的工作原理相同,但使用imshow()可以正确地转换格式。在iOS上,通过包装器返回,有一个格式转换问题…谢谢@foundry。我重建了框架只是为了确定,遇到了同样的问题。回顾UIImage+OpenCV,initWithCVMat希望每个像素有一个硬编码的8位通道,所以我想问题可以在这里解决,或者我可以在将图像移交给UIKit之前将其转换为OpenCV中的8位。您捕获了多少图像,时间是捕获每个图像的时间。它是?
- (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;
}