web-dev-qa-db-fra.com

Conversion de YUV en BGR ou RGB en OpenCV

J'ai une carte de capture de télévision avec un flux entrant au format YUV. J'ai vu d'autres articles ici similaires à cette question et j'ai essayé d'essayer toutes les méthodes possibles, mais aucun d'eux n'a fourni une image claire. Pour le moment, les meilleurs résultats ont été obtenus avec l’appel de fonction OpenCV cvCvtColor(scr, dst, CV_YUV2BGR).

Je ne suis pas au courant du format YUV et, pour être honnête, me laisse un peu perplexe, car on dirait qu'il stocke 4 canaux, mais seulement 3? J'ai inclus une image de la carte de capture pour espérer que quelqu'un puisse comprendre ce qui se passe éventuellement et que je pourrais utiliser pour compléter les blancs.

YUV to BGR converted image

Le flux provient d'une carte DeckLink Intensity Pro et est utilisé dans une application C++ via OpenCV dans un environnement Windows 7.

Mettre à jour

J'ai consulté un article de Wikipédia concernant cette information et tenté d'utiliser la formule dans mon application. Ci-dessous se trouve le bloc de code avec la sortie reçue. Tout conseil est grandement appréciée.

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

10
Seb

Il me semble que vous décodez un flux YUV422 en tant que YUV444. Essayez cette modification du code que vous avez fourni:

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);
}

Je ne suis pas sûr que vos constantes soient correctes, mais au pire, vos couleurs seront éteintes - l'image devrait être reconnaissable.

5
Mark Ransom

Dans la nouvelle version de OPENCV, une fonction intégrée peut être utilisée pour effectuer la conversion de YUV à RGB

cvtColor(src,dst,CV_YUV2BGR_YUY2);

spécifiez le format YUV après le trait de soulignement, comme ceci CV_YUYV2BGR_xxxx 

8
kyencn

Le logiciel BlackMagic Intensity renvoie le format YUVY 'dans bmdFormat8BitYUV, de sorte que 2 pixels de sources soient compressés en 4 octets - je ne pense pas que le cvtColor d’openCV puisse gérer cela.

Vous pouvez le faire vous-même ou simplement appeler la fonction ConvertFrame () du logiciel Intensity.

edit: Y U V est normalement stocké comme
enter image description here

Il y a un Y (luminosité) pour chaque pixel, mais seulement un U et un V (couleur) pour chaque pixel alternatif de la ligne.

Donc, si data est un caractère non signé pointant vers le début de la mémoire, comme indiqué ci-dessus.

pixel 1, Y = données [0] U = données [+1] V = données [+3]
pixel 2, Y = données [+2] U = données [+1] V = données [+3]

Ensuite, utilisez les coefficients YUV-> RVB que vous avez utilisés dans votre exemple de code.

2
Martin Beckett

J'utilise le code C++ suivant en utilisant OpenCV pour convertir les données yuv (YUV_NV21) en image rgb (BGR en 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;
}

et le résultat converti est comme l’image yuv.png .

vous pouvez trouver l'image brute de test de ici et l'ensemble du projet de mon projet Github

1
Hongchen Gao

Ce n'est peut-être pas le bon chemin, mais beaucoup de gens (les ingénieurs, par exemple) associent YUV à YCbCr. 

Essayez de 

cvCvtColor(src, dsc, CV_YCbCr2RGB) 

ou CV_YCrCb2RGB ou peut-être un type plus exotique. 

1
Sam

Peut-être que les modèles de couleurs YCbCr et YUV confondent quelqu'un. Opencv ne gère pas YCbCr . Au lieu de cela, il a YCrCb et il est mis en œuvre de la même manière que YUV in opencv. 

Des sources d'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)

Mais il y a encore une chose à dire.
Il y a actuellement unboguedans la conversion CV_BGR2YUV et CV_RGB2YUV dans la branche OpenCV 2.4. *.

À l'heure actuelle, cette formule est utilisée dans la mise en œuvre:

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

Ce que ce devrait être (selon wikipedia ):

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

Les canaux Rouge et Bleu sont mal placés dans la formule implémentée. 

Solution possible pour convertir BGR-> YUV alors que le bogue n'est pas corrigé:

  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
Temak