我正在使用opencv来实现对象跟踪。我读到YUV图像比RGB图像更好用。我的问题是我没有理解YUV格式,尽管我花了很多时间阅读笔记。 Y是我认为是由R,G,B组分的组合计算的亮度。
我的主要问题是如何访问和操作YUV图像格式的像素。在RGB格式中,它易于访问组件,因此可以使用像
这样的简单操作来更改它src.at<Vec3b>(j,i).val[0] = 0; for example
但在YUV中并非如此。我需要帮助访问和更改YUV图像中的像素值。例如,如果RGB中的像素是红色,那么我想仅保留YUV中的相应像素,其余部分被移除。请帮帮我。
答案 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>