YUV图像中的像素

时间:2013-05-13 03:30:09

标签: c++ opencv image-processing yuv

我正在使用opencv来实现对象跟踪。我读到YUV图像比RGB图像更好用。我的问题是我没有理解YUV格式,尽管我花了很多时间阅读笔记。 Y是我认为是由R,G,B组分的组合计算的亮度。

我的主要问题是如何访问和操作YUV图像格式的像素。在RGB格式中,它易于访问组件,因此可以使用像

这样的简单操作来更改它
src.at<Vec3b>(j,i).val[0] = 0; for example

但在YUV中并非如此。我需要帮助访问和更改YUV图像中的像素值。例如,如果RGB中的像素是红色,那么我想仅保留YUV中的相应像素,其余部分被移除。请帮帮我。

4 个答案:

答案 0 :(得分:4)

我建议您使用HSV或LAB而不是RGB来操作图像。

来自相机的原始图像将在YCbCr中(有时称为YUV,我认为这是不正确的,但我可能是错的),并且以类似于YUYV(重复)的方式布局,所以如果你能直接从它转换为HSV,您将避免额外的复制和转换操作,这将节省您一些时间。但是,如果您正在处理视频或批量图像,这可能只对您有用。

这里有一些用于在YCbCr和RGB之间进行转换的C ++代码(一个使用整数数学,另一个使用浮点数):

Colour::bgr Colour::YCbCr::toBgrInt() const
{
  int c0 = 22987;
  int c1 = -11698;
  int c2 = -5636;
  int c3 = 29049;

  int y = this->y;
  int cb = this->cb - 128;
  int cr = this->cr - 128;

  int b = y + (((c3 * cb) + (1 << 13)) >> 14);
  int g = y + (((c2 * cb + c1 * cr) + (1 << 13)) >> 14);
  int r = y + (((c0 * cr) + (1 << 13)) >> 14);

  if (r < 0)
    r = 0;
  else if (r > 255)
    r = 255;

  if (g < 0)
    g = 0;
  else if (g > 255)
    g = 255;

  if (b < 0)
    b = 0;
  else if (b > 255)
    b = 255;

  return Colour::bgr(b, g, r);
}

Colour::bgr Colour::YCbCr::toBgrFloat() const
{
  float y = this->y;
  float cb = this->cb;
  float cr = this->cr;

  int r = y + 1.40200 * (cr - 0x80);
  int g = y - 0.34414 * (cb - 0x80) - 0.71414 * (cr - 0x80);
  int b = y + 1.77200 * (cb - 0x80);

  if (r < 0)
    r = 0;
  else if (r > 255)
    r = 255;

  if (g < 0)
    g = 0;
  else if (g > 255)
    g = 255;

  if (b < 0)
    b = 0;
  else if (b > 255)
    b = 255;

  return Colour::bgr(b, g, r);
}

从BGR到HSV的转换:

Colour::hsv Colour::bgr2hsv(bgr const& in)
{
  Colour::hsv out;

  int const hstep = 255 / 3;            // Hue step size between red -> green -> blue

  int min = in.r < in.g ? in.r : in.g;
  min = min  < in.b ? min  : in.b;

  int max = in.r > in.g ? in.r : in.g;
  max = max  > in.b ? max  : in.b;

  out.v = max;                          // v
  int chroma = max - min;
  if (max > 0)
  {
    out.s = 255 * chroma / max;         // s
  }
  else
  {
    // r = g = b = 0                    // s = 0, v is undefined
    out.s = 0;
    out.h = 0;
    out.v = 0; // it's now undefined
    return out;
  }

  if (chroma == 0)
  {
    out.h = 0;
    return out;
  }

  const int chroma2 = chroma * 2;
  int offset;
  int diff;

  if (in.r == max)
  {
    offset = 3 * hstep;
    diff = in.g - in.b;
  }
  else if (in.g == max)
  {
    offset = hstep;
    diff = in.b - in.r;
  }
  else
  {
    offset = 2 * hstep;
    diff = in.r - in.g;
  }

  int h = offset + (diff * (hstep + 1)) / chroma2;

  // Rotate such that red has hue 0
  if (h >= 255)
    h -= 255;

  assert(h >= 0 && h < 256);

  out.h = h;

  return out;

不幸的是我没有代码可以一步完成。

您还可以使用built-in OpenCV functions for colour conversion

cvtColor(img, img, CV_BGR2HSV);

答案 1 :(得分:1)

U和V分量也被计算为RGB值的线性组合。那意味着,不同强度的红色(R,0,0)被映射到一些(y * R + a,u * R + b,v * R + c),这再次意味着检测到“红色” YUV可以计算由y,u,v,a,b,c(其中一些是冗余的)确定的像素到该线的距离是否接近零。单点产品可以实现这一点。然后将剩余像素设置为YUV空间中的(0,128,128)(我认为在几乎所有YCrCb,YUV等类型中,R = 0,G = 0,B = 0)。

答案 2 :(得分:1)

有几种YUV格式,但常见的格式保持Y与原始图像的分辨率相同,但U和V是半角,并在单通道Y图像缓冲区后保存为单独或隔行扫描的平面/通道。

这使您可以有效地访问Y作为1通道8位灰度图像。

答案 3 :(得分:0)

访问和操作像素不知道颜色格式,因此相同的代码适用于颜色分量YU和V.如果需要以RGB模式访问,最好可能首先为您感兴趣的区域调用cv::cvtColor。 / p>