Преобразование YUV в BGR или RGB в OpenCV - PullRequest
10 голосов
/ 31 октября 2011

У меня есть карта захвата телевидения, в которой есть канал в формате YUV.Я видел другие посты, похожие на этот вопрос, и пытался попробовать все возможные методы, но ни один из них не дал четкого изображения.На данный момент наилучшие результаты были получены при вызове функции OpenCV cvCvtColor(scr, dst, CV_YUV2BGR).

В настоящее время я не знаю формат YUV и, честно говоря, меня немного смущает, так как в нем хранятся 4 канала, нотолько 3?Я включил изображение с карты захвата, чтобы надеяться, что кто-то может понять, что, возможно, происходит, что я мог бы использовать для заполнения пробелов.

YUV to BGR converted image

Фид приходитчерез карту DeckLink Intensity Pro и доступ к ней в приложении C ++ при использовании OpenCV в среде Windows 7.

Обновление

Я смотрел статью в Википедии об этоминформация и попытался использовать формулу в моем приложении.Ниже приведен блок кода с полученным из него выводом.Любой совет с благодарностью.

BYTE* pData;

    videoFrame->GetBytes((void**)&pData);

    m_nFrames++;

    printf("Num Frames executed: %d\n", m_nFrames);

    for(int i = 0; i < 1280 * 720 * 3; i=i+3)
    {
        m_RGB->imageData[i] = pData[i] + pData[i+2]*((1 - 0.299)/0.615);
        m_RGB->imageData[i+1] = pData[i] - pData[i+1]*((0.114*(1-0.114))/(0.436*0.587)) - pData[i+2]*((0.299*(1 - 0.299))/(0.615*0.587));
        m_RGB->imageData[i+2] = pData[i] + pData[i+1]*((1 - 0.114)/0.436);
    }

Attempted RGB conversion

Ответы [ 6 ]

8 голосов
/ 18 апреля 2014

В более новой версии OPENCV есть встроенная функция, которая может использоваться для преобразования YUV в RGB

cvtColor(src,dst,CV_YUV2BGR_YUY2);

укажите формат YUV после подчеркивания, например CV_YUYV2BGR_xxxx

5 голосов
/ 01 ноября 2011

Мне кажется, что вы декодируете поток YUV422 как YUV444. Попробуйте изменить код, который вы указали:

for(int i = 0, j=0; i < 1280 * 720 * 3; i+=6, j+=4)
{
    m_RGB->imageData[i] = pData[j] + pData[j+3]*((1 - 0.299)/0.615);
    m_RGB->imageData[i+1] = pData[j] - pData[j+1]*((0.114*(1-0.114))/(0.436*0.587)) - pData[j+3]*((0.299*(1 - 0.299))/(0.615*0.587));
    m_RGB->imageData[i+2] = pData[j] + pData[j+1]*((1 - 0.114)/0.436);
    m_RGB->imageData[i+3] = pData[j+2] + pData[j+3]*((1 - 0.299)/0.615);
    m_RGB->imageData[i+4] = pData[j+2] - pData[j+1]*((0.114*(1-0.114))/(0.436*0.587)) - pData[j+3]*((0.299*(1 - 0.299))/(0.615*0.587));
    m_RGB->imageData[i+5] = pData[j+2] + pData[j+1]*((1 - 0.114)/0.436);
}

Я не уверен, что у вас правильные константы, но в худшем случае ваши цвета будут отключены - изображение должно быть узнаваемым.

2 голосов
/ 18 ноября 2018

Я использую следующий код C ++ с использованием OpenCV для преобразования данных yuv (YUV_NV21) в изображение rgb (BGR в OpenCV)

int main()
{
  const int width  = 1280;
  const int height = 800;

  std::ifstream file_in;
  file_in.open("../image_yuv_nv21_1280_800_01.raw", std::ios::binary);
  std::filebuf *p_filebuf = file_in.rdbuf();
  size_t size = p_filebuf->pubseekoff(0, std::ios::end, std::ios::in);
  p_filebuf->pubseekpos(0, std::ios::in);

  char *buf_src = new char[size];
  p_filebuf->sgetn(buf_src, size);

  cv::Mat mat_src = cv::Mat(height*1.5, width, CV_8UC1, buf_src);
  cv::Mat mat_dst = cv::Mat(height, width, CV_8UC3);

  cv::cvtColor(mat_src, mat_dst, cv::COLOR_YUV2BGR_NV21);
  cv::imwrite("yuv.png", mat_dst);

  file_in.close();
  delete []buf_src;

  return 0;
}

и преобразованный результат похож на изображение yuv.png .

вы можете найти необработанное тестовое изображение из здесь и весь проект из моего Проект Github

2 голосов
/ 01 ноября 2011

Программное обеспечение BlackMagic Intensity возвращает формат YUVY 'в bmdFormat8BitYUV, поэтому 2 исходных пикселя сжимаются в 4 байта - я не думаю, что cvtColor из openCV справится с этим.

Вы можете сделать это самостоятельно или просто вызвать функцию ConvertFrame () программного обеспечения Intensity

edit: Y U V обычно сохраняется как
enter image description here

Существует Y (яркость) для каждого пикселя, но только U и V (цвет) для каждого альтернативного пикселя в строке.

То есть, если данные представляют собой беззнаковый символ, указывающий на начало памяти, как показано выше.

пиксель 1, Y = данные [0] U = данные [+1] V = данные [+3]
пиксель 2, Y = данные [+2] U = данные [+1] V = данные [+3]

Затем используйте коэффициенты YUV-> RGB, которые вы использовали в своем примере кода.

1 голос
/ 27 апреля 2015

Возможно, кого-то смущают цветовые модели YCbCr и YUV.Opencv не обрабатывает YCbCr .Вместо этого он имеет YCrCb , и он реализован так же, как YUV в opencv.

Из исходников opencv https://github.com/Itseez/opencv/blob/2.4/modules/imgproc/src/color.cpp#L3830:

case CV_BGR2YCrCb: case CV_RGB2YCrCb:
case CV_BGR2YUV: case CV_RGB2YUV:
    // ...
    // 1 if it is BGR, 0 if it is RGB
    bidx = code == CV_BGR2YCrCb || code == CV_BGR2YUV ? 0 : 2; 
    //... converting to YUV with the only difference that brings 
    //    order of Blue and Red channels (variable bidx)

Но есть еще кое-что, что можно сказать.
В настоящее время есть ошибка в преобразовании CV_BGR2YUV и CV_RGB2YUV в ветви OpenCV 2.4. *.

В настоящее время эта формула используется в реализации:

Y = 0.299B + 0.587G + 0.114R
U = 0.492(R-Y)
V = 0.877(B-Y)

Что это должно быть (согласно wikipedia ):

Y = 0.299R + 0.587G + 0.114B
U = 0.492(B-Y)
V = 0.877(R-Y)

Каналы Red и Blue смещены в реализованной формуле.

Возможный обходной путь для преобразования BGR-> YUV, пока ошибка не устранена:

  cv::Mat source = cv::imread(filename, CV_LOAD_IMAGE_COLOR);
  cv::Mat yuvSource;    
  cvtColor(source, yuvSource, cv::COLOR_BGR2RGB); // rearranges B and R in the appropriate order
  cvtColor(yuvSource, yuvSource, cv::COLOR_BGR2YUV);
  // yuvSource will contain here correct image in YUV color space
1 голос
/ 31 октября 2011

Это может быть неправильный путь, но многие люди (я имею в виду инженеров) смешивают YUV с YCbCr.

Попробуйте

cvCvtColor(src, dsc, CV_YCbCr2RGB) 

или CV_YCrCb2RGB или, возможно, более экзотический тип.

...