【问题标题】:BGR -> YCbCr conversion not working correctlyBGR -> YCbCr 转换无法正常工作
【发布时间】:2019-06-23 15:05:19
【问题描述】:

我正在尝试手动将图像从 RBG(OpenCV 中的 BGR)转换为 YCbCr 颜色空间。

我的图像是png 彩色图像,宽度为 800,高度为 600,3 通道,16 位深度。

这是我尝试解决此问题的方法。

cv::Mat convertToYCbCr(cv::Mat image) {                                         
    // converts an RGB image to YCbCr                                           
    // cv::Mat: B-G-R                                                           
    std::cout << "Converting image to YCbCr color space." << std::endl;         
    int i, j;                                                                   
    for (i = 0; i <= image.cols; i++) {                                         
        for (j = 0; j <= image.rows; j++) {                                     

            // R, G, B values                                                   
            auto R = image.at<cv::Vec3d>(j, i)[2];                              
            auto G = image.at<cv::Vec3d>(j, i)[1];                              
            auto B = image.at<cv::Vec3d>(j, i)[0];                              

            // Y'                                                               
            auto Y = image.at<cv::Vec3d>(j,i)[0] = 0.299 * R + 0.587 * G + 0.114 * B + 16;

            // Cb                                                               
            auto Cb = image.at<cv::Vec3d>(j,i)[1] = 128 + (-0.169 * R -0.331 * G + 0.5 * B);

            // Cr                                                               
            auto Cr = image.at<cv::Vec3d>(j,i)[2] = 128 + (0.5 * R -0.419 * G -0.081 * B);
            std::cout << "At conversion: Y = " << Y << ", Cb = " << Cb << ", "  
                << Cr << std::endl;                                             
        }                                                                       
    }                                                                           
    std::cout << "Converting finished." << std::endl;                           
    return image;                                                               
}

我收到的图像如下所示:

我期待的是这个(使用 OpenCV 方法):

垂直线暗示着什么?我的循环错了吗?我什至可以用 YCbCr 值“替换”RGB 值并期望图像看起来像示例吗? typeid() 为两个图像返回相同的值,N2cv3MatE

【问题讨论】:

  • Vec3d 是 3x64 位。你有什么理由使用这种类型吗?您是否尝试过 Vec3b?
  • 这确实解决了问题,谢谢!是的,出于某种原因,我只是假设它是双重类型。您可以将此作为答案发布,我会接受。
  • @mneumann,如果您说图像具有 16 位深度,使用 Vec3b 是如何解决您的问题的? Vec3b 用于 8 位图像。

标签: c++ opencv


【解决方案1】:

观察到错误结果的主要原因是用于访问图像的数据类型不正确。访问 16 位无符号像素的正确类型是 cv::Vec3w(不是 cv::Vec3d)。

下一个问题是用于转换的系数是为模拟信号 (YPbPr) 设计的。对于数字图像,我们必须使用为数字图像设计的系数 (YCbCr)。您可以在 ITU-R BT.601 转换部分找到有关 Wikipedia article on YCbCr 的更多详细信息。

文章中缺少的一条信息是,如果图像是 16 位无符号深度或 32 位浮点深度,系数将如何变化?答案是我们必须根据图像的位深度来缩放系数。

对于 16 位无符号深度的图像,应按如下方式进行缩放:

auto Y = (R * 65.481f * scale) + (G * 128.553f * scale) + (B * 24.966f * scale) + (16.0f * offset);
auto Cb = (R * -37.797f * scale) + (G * -74.203f * scale) + (B * 112.0f * scale) + (128.0f * offset);
auto Cr = (R * 112.0f * scale) + (G * -93.786f * scale) + (B * -18.214f * scale) + (128.0f * offset);

其中scale 等于257.0/65535.0 并且offset 等于257.0

此转换技术已从 rgb2ycbcr 函数的 MATLAB 源代码中采用,该函数引用了以下描述缩放的书籍:

C.A. Poynton,“数字视频技术介绍”,John Wiley & Sons, Inc.,1996 年,第 9 章,第 175 页`

现在转换已经完成,我们面临的第三个问题是类似于OpenCV的图像可视化。当我们使用 OpenCV 执行颜色转换时,输出图像以YCrCb 的顺序存储,而不是通常的YCbCr。因此,要使用我们的自定义转换逻辑获得相同的图像,我们必须按相关顺序存储值。

示例转换代码可能如下所示:

if(image.type() == CV_16UC3)
{
    const float scale = 257.0f / 65535.0f;
    const float offset = 257.0f;
    for (int i = 0; i < image.cols; i++)
    {
        for (int j = 0; j < image.rows; j++)
        {
            auto R = image.at<cv::Vec3w>(j, i)[2];
            auto G = image.at<cv::Vec3w>(j, i)[1];
            auto B = image.at<cv::Vec3w>(j, i)[0];

            auto Y = (R * 65.481f * scale) + (G * 128.553f * scale) + (B * 24.966f * scale) + (16.0f * offset);
            auto Cb = (R * -37.797f * scale) + (G * -74.203f * scale) + (B * 112.0f * scale) + (128.0f * offset);
            auto Cr = (R * 112.0f * scale) + (G * -93.786f * scale) + (B * -18.214f * scale) + (128.0f * offset);

            image.at<cv::Vec3w>(j, i)[0] = (unsigned short)Y;
            image.at<cv::Vec3w>(j, i)[1] = (unsigned short)Cr;
            image.at<cv::Vec3w>(j, i)[2] = (unsigned short)Cb;
        }
    }
}

【讨论】:

    【解决方案2】:

    你应该使用cv::cvtColor

    cvtColor(src, target_image, cv::COLOR_RGB2YCrCb);
    

    然后只需翻转第二和第三个通道。

    虽然您可能会收到该错误,因为您没有将结果值转换为整数。

    【讨论】:

    • 这是作业,我不能使用该功能。实际上,我已经将它用于参考图像。有机会我会试试打字,谢谢!
    猜你喜欢
    • 2013-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多