Я использую OpenCV для достижения отслеживания объектов. Я читал, что YUV-изображение — лучший вариант, чем RGB-изображение. Моя проблема в том, что я не понимаю формата YUV, хотя я провожу много времени за чтением заметок. Y — яркость, которая, как я считаю, рассчитывается из комбинации компонентов R, G, B.
Моя основная проблема заключается в том, как я могу получить доступ к пикселям в формате изображения YUV и управлять ими. В формате RGB легко получить доступ к компоненту и, следовательно, изменить его, используя простые операции, такие как
src.at<Vec3b>(j,i).val[0] = 0; for example
Но это не так в YUV. Мне нужна помощь в доступе и изменении значений пикселей в изображении YUV. Например, если пиксель в RGB красный, то я хочу оставить только соответствующий пиксель в YUV, а остальное удалить. Пожалуйста, помогите мне с этим.
Я бы предложил работать с вашим изображением в формате HSV или LAB, а не RGB.
Необработанное изображение с камеры будет в YCbCr (иногда называемом YUV, что я считаю неправильным, но я могу ошибаться), и выложено таким образом, что напоминает что-то вроде YUYV (повторяющееся), так что если вы можете преобразовать напрямую из что для HSV, вы избежите дополнительных операций копирования и преобразования, которые сэкономят вам время. Это может иметь значение только для вас, если вы обрабатываете видео или пакеты изображений.
Вот некоторый код C ++ для преобразования между YCbCr и RGB (один использует целочисленную математику, другой — с плавающей запятой):
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);
Также компоненты U и V рассчитываются как линейные комбинации значений RGB. Тогда это означает, что различные интенсивности красного (R, 0,0) отображаются на некоторые (y * R + a, u * R + b, v * R + c), что снова означает, что для обнаружения «красного» в YUV можно вычислить, если расстояние от пикселя до этой линии, определяемое y, u, v, a, b, c (некоторые из которых являются избыточными), близко к нулю. Это достижимо с помощью единственного точечного продукта. Затем установите оставшиеся пиксели в (0,128,128) в пространстве YUV (я думаю, что это R = 0, G = 0, B = 0 почти во всех вариантах YCrCb, YUV и т. Д.).
Существует несколько форматов YUV, но общие поддерживают Y с тем же разрешением, что и исходное изображение, но U и V имеют половинный размер и сохраняются в виде отдельных или чересстрочных плоскостей / каналов после буфера изображения Y одного канала.
Это позволяет эффективно обращаться к Y как 8-битному 1-канальному изображению в оттенках серого.
Доступ к пикселям и манипулирование ими не знает цветовой формат, поэтому тот же код применяется для цветовых компонентов Y U и V. Если вам нужен доступ в режиме RGB, лучше всего вызывать cv::cvtColor
для вашего региона интересов в первую очередь.