OpenCV矩阵操作导致YUV图像的颜色损坏

时间:2016-11-01 17:11:43

标签: c++ opencv image-processing

我正在尝试在一个YUV格式的OpenCV图像上进行图像稳定,其中有2个通道:一个包含Y值,另一个包含交替的U / V值(OpenCV中的YUV_YUY2)。

我遇到的问题是某些矩阵运算,特别是warpAffine和resize,可以移动数组,使得U值最终在V位置,反之亦然,反转颜色或在图像中引起条纹。 / p>

我的第一个想法是我可以将图像转换为不同的(非交错的)图像类型,应用转换,然后转换回来,但是使用我发现的cvtColor()的可用转换:http://docs.opencv.org/3.1.0/d7/d1b/group__imgproc__misc.html

我可以从YUV_YUY2转换为其他格式,但没有可用的转换回YUV_YUY2格式。

我或许可以手动重建YUY2矩阵,但我怀疑这可能是一种我更容易丢失的方法。任何OpenCV大师有什么建议吗?感谢。

代码段:

cv::Mat stabilize (VideoFrame* curFrame, VideoFrame* prevFrame)
{
   Mat locCurMat, locPrevMat;
   locCurMat = Mat(1080, 1920, CV_8UC2, curFrame->video);
   locPrevMat = Mat(1080, 1920, CV_8UC2, prevFrame->video);

   // Calculate the transformation matrix
   Mat locTransform;
   // I’ll spare you this part
   // …

   // Apply the transformation
   Mat locStabFrame;
   // Make the border value (0, 128) for black: 
   // If you leave it at 0,0 it's bright green
   Scalar locBorderVal(0, 128);
   warpAffine(locCurMat, locStabFrame, locTransform, locCurMat.size(),
              INTER_LINEAR, BORDER_CONSTANT, locBorderVal);

   // Crop the borders to make the video look better
   // Get the aspect ratio correct
   int locVertBorder = HORIZONTAL_BORDER_CROP * 
                       locCurMat.rows / locCurMat.cols;
   locStabFrame = locStabFrame(
       Range(locVertBorder, locStabFrame.rows - locVertBorder),
       Range(HORIZONTAL_BORDER_CROP,
             locStabFrame.cols - HORIZONTAL_BORDER_CROP));

   // Resize locStabFrame back to the proper frame size
   resize(locStabFrame, locStabFrame, locCurMat.size());

   // Return the stabilized result
   return locStabFrame;
}

1 个答案:

答案 0 :(得分:0)

如果有人有兴趣,这是我为避免这个问题而采取的流程。但是它很流氓,如果有人有更高效的方式,我会很高兴听到它。

步骤基本上是:

  1. 在2通道YUV
  2. 中为u值和v值创建掩码
  3. 从2通道YUV转换为RGB
  4. 运行warpAffine&调整RGB图像大小
  5. 将RGB转换为3通道YUV
  6. 使用u / v掩码从3通道YUV重建2通道YUV
  7. 返回2频道YUV图像
  8. 代码:

    // Apply the transformation
    Mat rgbFrame, stabFrame, outputFrame;
    // Convert the frame to RGB
    cvtColor(locCurMat, rgbFrame, COLOR_YUV2RGB_YUY2);
    
    // Apply the image translation
    warpAffine(rgbFrame, stabFrame, T, rgbFrame.size());
    
    // Crop the borders to make the video look better
    // Get the aspect ratio correct
    int vert_border = HORIZONTAL_BORDER_CROP * locCurMat.rows / locCurMat.cols;
    stabFrame = stabFrame(Range(vert_border, stabFrame.rows - vert_border),
                          Range(HORIZONTAL_BORDER_CROP,
                                stabFrame.cols - HORIZONTAL_BORDER_CROP));
    
    
    // Resize regFrame back to the correct frame size
    resize(stabFrame, stabFrame, rgbFrame.size());
    
    // Convert back from RGB to YUV
    // First, see if the u/v masks are the correct size, and populate them
    // if not. Hopefully this only happens once
    if (locCurMat.rows != m_uMask.rows || locCurMat.cols != m_uMask.cols)
    {
         printf("Creating U/V image masks\n");
         m_uMask = cv::Mat::zeros(locCurMat.size(), CV_8UC1);
         m_vMask = cv::Mat::zeros(locCurMat.size(), CV_8UC1);
         cv::Mat onesCol = cv::Mat::ones(locCurMat.rows, 1, CV_8UC1);
         // Populate the masks with alternating columns of 1s
         for (int i = 0; i < locCurMat.cols; i++)
         {
             // Copy even columns to the u mask
             if (i % 2 == 0)
             {
                 onesCol.copyTo(m_uMask.col(i));
             }
             // Copy odd columns to the v mask
             else
             {
                 onesCol.copyTo(m_vMask.col(i));
             }
          }
      }
    
    // Convert the stabilized rgb frame to YUV
    Mat yuvFrame;
    cvtColor(stabFrame, yuvFrame, COLOR_RGB2YUV);
    
    // Split the YUV frame into individual channels
    vector<Mat> yuv3Channels;
    split(yuvFrame, yuv3Channels);
    
    // Copy the 3 channel YUV values into 2 channel YUV
    vector<Mat> yuv2Channels;
    Mat uvChannel;
    yuv3Channels[1].copyTo(uvChannel, m_uMask);
    yuv3Channels[2].copyTo(uvChannel, m_vMask);
    yuv2Channels.push_back(yuv3Channels[0]);
    yuv2Channels.push_back(uvChannel);
    
    // Merge the 2 channel yuv back into the output frame
    cv::merge(yuv2Channels, outputFrame);