Преобразование YUV в BGR или RGB в OpenCV

#c #windows #opencv #video-streaming

#c #Windows #opencv #потоковое видео

Вопрос:

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

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

Преобразованное изображение YUV в BGR

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

Обновить

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

 BYTE* pData;

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

    m_nFrames  ;

    printf("Num Frames executed: %dn", 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);
    }
 

Попытка преобразования RGB

Комментарии:

1. «В настоящее время я не знаю о формате YUV» -> Википедия. Прочитайте об этом: en.wikipedia.org/wiki/YUV#Conversion_to . 2Ffrom_RGB

2. Спасибо за ссылку на эту статью, но должен ли я предполагать, что я буду работать с y, u, v и y1 и использовать эти переменные для создания эквивалента RGB? Кроме того, должен ли я создать 4 разных массива для приема каждого отдельного набора значений, чтобы объединить их все вместе?

3. Вам понадобится всего 3 массива, поскольку в RGB есть 3 цветовых компонента. Но да, вам в основном нужно вычислять цветовые компоненты по отдельности и где-то их хранить.

Ответ №1:

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

cvtColor(src,dst,CV_YUV2BGR_YUY2);

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

Комментарии:

1. Это будет работать правильно, только если источником YUV является SD. Это может выглядеть правильно при базовом визуальном осмотре, но цвета на самом деле неверны. Это связано с тем, что последний на данный момент исходный код OpenCV (2.4.10) для преобразования YUV поддерживает только 601 цветовое пространство PAL / NTSC / SECAM, а не 709 HD или 2020 UHD.

Ответ №2:

Мне кажется, что вы декодируете поток 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);
}
 

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

Комментарии:

1. Вы были правы в том, что константы неверны. Я вижу красивое и четкое изображение. Мне просто нужно исследовать константы YUV422, чтобы исправить проблему. Спасибо за этот совет.

Ответ №3:

Я использую следующий код на 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

Ответ №4:

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

Попробуйте

 cvCvtColor(src, dsc, CV_YCbCr2RGB) 
 

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

Комментарии:

1. Мои извинения, это CV_YCbCr. В OpenCV нет перечислителя YUV.

2. Это будет работать правильно, только если источником YUV является SD. Это может выглядеть правильно при базовом визуальном осмотре, но цвета на самом деле неверны. Это связано с тем, что последний на данный момент исходный код OpenCV (2.4.10) для преобразования YUV поддерживает только 601 цветовое пространство PAL / NTSC / SECAM, а не 709 HD или 2020 UHD.

3. В Opencv 2.4. * есть перечислитель YUV и нет CV_YCbCr2RGB. Вместо этого есть CV_YCrCb2RGB.

Ответ №5:

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

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

редактировать: YUV обычно сохраняется как
введите описание изображения здесь

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

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

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

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

Комментарии:

1. Я изучил эту функцию, но она не работает в классе IDeckLinkInputFrame. Казалось бы, лучший способ сделать это самостоятельно. Спасибо, что упомянули, что такое YUVY, но не знаете ли вы случайно формулу конверсии, основанную на том, на что вы наткнулись? Если вы понятия не имеете, пожалуйста, не пытайтесь мне помочь. Спасибо

2. возможно, ps неправильно использовал U / V Cr / Cb — но это должно быть очевидно!

Ответ №6:

Может быть, кого-то смущают цветовые модели 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)
 

Каким он должен быть (согласно википедии):

 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