Пиксели в 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

Решение

Я бы предложил работать с вашим изображением в формате 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);
4

Другие решения

Также компоненты 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 и т. Д.).

1

Существует несколько форматов YUV, но общие поддерживают Y с тем же разрешением, что и исходное изображение, но U и V имеют половинный размер и сохраняются в виде отдельных или чересстрочных плоскостей / каналов после буфера изображения Y одного канала.

Это позволяет эффективно обращаться к Y как 8-битному 1-канальному изображению в оттенках серого.

1

Доступ к пикселям и манипулирование ими не знает цветовой формат, поэтому тот же код применяется для цветовых компонентов Y U и V. Если вам нужен доступ в режиме RGB, лучше всего вызывать cv::cvtColor для вашего региона интересов в первую очередь.

0
По вопросам рекламы [email protected]