【问题标题】:Pixels in YUV imageYUV 图像中的像素
【发布时间】:2013-05-13 03:30:09
【问题描述】:

我正在使用opencv来实现对象跟踪。我读到 YUV 图像比 RGB 图像更适合使用。我的问题是,虽然我花了很多时间阅读笔记,但我对 YUV 格式并不了解。 Y 是我认为是根据 R、G、B 分量的组合计算得出的亮度。

我的主要问题是如何访问和操作 YUV 图像格式的像素。在 RGB 格式中,它很容易访问组件,因此可以使用简单的操作来更改它,例如

src.at<Vec3b>(j,i).val[0] = 0; for example

但在 YUV 中情况并非如此。我需要帮助来访问和更改 YUV 图像中的像素值。例如,如果 RGB 中的像素是红色的,那么我只想在 YUV 中保留相应的像素,其余的被删除。请帮我解决这个问题。

【问题讨论】:

  • 在什么情况下,YUV 优于 RGB?如果要过滤红色像素,我推荐 RGB(用于简单图像)或 HSV(用于自然图像)。
  • 因为照片的照明很多不同,所以我认为 YUV 可能是一个更好的选择
  • 大多数相机实际上在 YCbCr 中捕获(非常相似,有时被视为与 YUV 相同),因此如果您使用 OpenCV 正确设置相机控件,则可以直接访问此 YCbCr 图像。我现在正在开发一个在图像中进行对象检测的系统,到目前为止,我们发现在 HSV 颜色空间中标记图像是最成功的。我读过 LAB 空间也可以提供良好的结果,具体取决于问题。
  • @DrewNoakes 用于对象检测的图像处于受控环境或不受控环境
  • 我的理解是,大多数相机使用 YUV,因为人眼对亮度(亮度)的变化比对色度(颜色)的变化更敏感。计算机视觉系统可能并不关心这一点。无论如何,在 HSV 空间中,您会发现“相似”颜色往往比它们在 RGB 中更接近。或者换一种说法,HSV 中两种颜色之间的 3D 距离比 RGB 更接近人类的理解。

标签: c++ opencv image-processing yuv


【解决方案1】:

我建议在 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);

【讨论】:

  • 谢谢。实际上我正在使用opencv并将其转换为HSV。但是您的代码很有帮助,因为我了解转换的基本方法。因为我的图像(帧)是 RGB 格式的静止图像,因此我认为我会将其从 RGB 转换为 HSV,因为目前时间对我来说不是问题。然而,我意识到一些让我吃惊的事情。也就是说,如果我在视觉上转换为 YUV,我认为感兴趣的对象颜色特征变得更加相关。不幸的是,也许我不正确,但我对使用哪一个感到困惑。目前我正在使用 HSV。
  • 我正在考虑两者都尝试,然后看看哪个更好。在这种情况下,我将与您分享结果。
  • 不是更好用的颜色转换内置函数吗?
  • 这取决于您的情况以及您如何更好地定义。
【解决方案2】:

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)。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 也许我还是有点困惑,尽管你解释得很好。我知道 Y 是单通道,但假设我有红色像素,所以 RGB = {255,0,0}。此外,我想将这个红色更改为绿色让我们说。我怎样才能在此基础上更改 Y。对不起,如果我听起来太混乱了
    • Y 是 R、G 和 B 的组合。它是图像的灰度版本的图像强度(或亮度)。如果您想切换颜色通道,您应该转换为 RGB 并在该空间中工作。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-22
      • 1970-01-01
      • 1970-01-01
      • 2012-02-29
      • 1970-01-01
      • 2012-01-19
      • 2017-04-23
      • 1970-01-01
      相关资源
      最近更新 更多