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