C++ 使用OpenCV对佳能CR2图像进行去层处理

C++ 使用OpenCV对佳能CR2图像进行去层处理,c++,image,opencv,canon-sdk,libraw,C++,Image,Opencv,Canon Sdk,Libraw,我要做的是读取我的佳能叛军T51200D拍摄的.cr2原始文件。我可以使用LibRaw和OpenCV加载和显示图像,但是图像看起来有点太亮,比在Windows中打开文件时更黄。图片本身在文章的底部。已经提出了几个类似的问题: 我将首先发布所有代码,然后讨论问题的细节 // Open the CR2 file with LibRaw, unpack, and create image LibRaw lrProc; assert( LIBRAW_SUCCESS == lrProc.open_fi

我要做的是读取我的佳能叛军T51200D拍摄的.cr2原始文件。我可以使用LibRaw和OpenCV加载和显示图像,但是图像看起来有点太亮,比在Windows中打开文件时更黄。图片本身在文章的底部。已经提出了几个类似的问题:

我将首先发布所有代码,然后讨论问题的细节

// Open the CR2 file with LibRaw, unpack, and create image
LibRaw lrProc;
assert( LIBRAW_SUCCESS == lrProc.open_file( "001.cr2" ) );
assert( LIBRAW_SUCCESS == lrProc.unpack() );
assert( LIBRAW_SUCCESS == lrProc.raw2image() );

// Get image dimensions
int width = lrProc.imgdata.sizes.iwidth;
int height = lrProc.imgdata.sizes.iheight;

// Create a buffer of ushorts containing the pixel values of the "BG Bayered" image
std::vector<ushort> vBayerData;
for ( int y = 0; y < height; y++ )
{
    for ( int x = 0; x < width; x++ )
    {
        // Get pixel idx
        int idx = y * width + x;

        // Each pixel is an array of 4 shorts rgbg
        ushort * uRGBG = lrProc.imgdata.image[idx];

        // Even rows are RGRGRG..., odd are GBGBGB...
        // For even rows, get either red or green, store in vec
        if ( y % 2 == 0 )
        {
            bool red = x % 2 == 0;
            vBayerData.push_back( uRGBG[red ? 0 : 1] );
        }
        // For odd rows, get either blue or green
        else
        {
            bool green = x % 2 == 0;
            vBayerData.push_back( uRGBG[green ? 3 : 2] );
        }
    }
}

// Get rid of libraw image, construct openCV mat
lrProc.recycle();
cv::Mat imgBayer( height, width, CV_16UC1, vBayerData.data() );

// Debayer image, get output
cv::Mat imgDeBayer;
cv::cvtColor( imgBayer, imgDeBayer, CV_BayerBG2RGB );

// The pixel color values were 12 bit, but our data is 16 bit
// transform the range [0, 4095] to [0:65535] (multiply by 16)
imgDeBayer *= 16;

// Display image
cv::namedWindow( "CR2 File", CV_WINDOW_FREERATIO );
cv::imshow( "CR2 File", imgDeBayer );
cv::waitKey();
因此,在偶数行上,红色和绿色1像素交替具有非零值,而在奇数行上,蓝色和绿色2像素交替具有非零值。这些值似乎是12位的,尽管我不是100%赞成

查看OpenCV的cvtColor函数的描述

以及此人对一些cr2颜色格式的描述:

向我表明我有一个“BG”品种的拜耳图像(按照OpenCV文档中使用的术语)

因此,为了将该图像传递给cvtColor,我必须从未打包的原始图像中获取每个像素值,并创建一个无符号短裤的连续图像。 //获取像素idx int idx=y*宽度+x

// Each pixel is an array of 4 shorts rgbg
ushort * uRGBG = lrProc.imgdata.image[idx];

// For even rows, get either red or green, store in vec
if ( y % 2 == 0 )
{
    bool red = x % 2 == 0;
    vBayerData.push_back( uRGBG[red ? 0 : 1] );
}
// For odd rows, get either blue or green
else
{
    bool green = x % 2 == 0;
    vBayerData.push_back( uRGBG[green ? 3 : 2] );
}
一旦我有了一个连续的短裤缓冲区(vBayerData),我就构建了一个opencv垫,并使用CV_BayerBG2RGB对其进行去层

但是,看看我打印出来的像素值告诉我,这些值可能是12位的(虽然我不完全确定),所以我必须从12位范围到16位范围,我相信这等于将这些值乘以16

// Construct bayer image from data
cv::Mat imgBayer( height, width, CV_16UC1, vBayerData.data() );

// Debayer image, get output
cv::Mat imgDeBayer;
cv::cvtColor( imgBayer, imgDeBayer, CV_BayerBG2RGB );

// The pixel color values were 12 bit, but our data is 16 bit
// transform the range [0, 4095] to [0:65535] (multiply by 16)
imgDeBayer *= 16;
在所有这些之后,这是我留下的图像:

然而,这是我的眼睛看到的(很抱歉缩放,颜色才是最重要的):

我觉得我离这里太近了,但是我得到的图像有点太亮,有点褪色。我相机上的设置是使用sRGB格式导出原始图像,因此我确信对图像强度应用某种伽马校正会有所帮助,但我似乎无法获得正确的图像

我尝试过不同的拜耳矩阵(即RG),不同的位深度转换,在进行位深度转换时重新排列(在脱层之前和之后),但似乎没有一个能使图像正确显示

有人认识这种变色吗?如果是这样,他们能帮我找到代码中的错误吗

谢谢你的阅读

约翰

另外,我知道这里有很多文本,我不确定这样的帖子的最佳格式是什么。我只是想提供我正在处理的所有信息

编辑: 正如Mark Ransom在下面所建议的,我认为这是由于白平衡不正确造成的。我被指向了这个方向,解码一幅图像不仅仅是debayer步骤

维基百科文章:

典型部件包括图像传感器校正(包括 “降低”或应用拜耳滤波器)、降噪、图像 缩放、伽马校正、图像增强、色彩空间转换 (在RGB、YUV或YCbCr等格式之间)、色度子采样、, 帧率转换、图像压缩/视频压缩(例如 JPEG),以及计算机数据存储/数据传输


一个简单的de Bayer不会应用任何白平衡校正。用白炽灯拍摄的照片会有点黄。可以通过应用2.2的gamma并拉伸结果的对比度来修复亮度问题。
// Each pixel is an array of 4 shorts rgbg
ushort * uRGBG = lrProc.imgdata.image[idx];

// For even rows, get either red or green, store in vec
if ( y % 2 == 0 )
{
    bool red = x % 2 == 0;
    vBayerData.push_back( uRGBG[red ? 0 : 1] );
}
// For odd rows, get either blue or green
else
{
    bool green = x % 2 == 0;
    vBayerData.push_back( uRGBG[green ? 3 : 2] );
}
// Construct bayer image from data
cv::Mat imgBayer( height, width, CV_16UC1, vBayerData.data() );

// Debayer image, get output
cv::Mat imgDeBayer;
cv::cvtColor( imgBayer, imgDeBayer, CV_BayerBG2RGB );

// The pixel color values were 12 bit, but our data is 16 bit
// transform the range [0, 4095] to [0:65535] (multiply by 16)
imgDeBayer *= 16;