4

我正在使用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

4 回答 4

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;

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

您还可以使用内置的 OpenCV 函数进行颜色转换

cvtColor(img, img, CV_BGR2HSV);
于 2013-05-13T10:02:01.403 回答
1

YUV 格式有多种,但常见的保持 Y 与原始图像相同的分辨率,但 U 和 V 是一半大小,在单通道 Y 图像缓冲区之后保存为单独或交错的平面/通道。

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

于 2013-05-13T08:10:15.887 回答
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)。

于 2013-05-13T05:40:24.127 回答
0

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

于 2013-05-13T07:52:59.287 回答