YUV格式转换为RGB(基于opencv)

之前写代码过程中需要将YUV格式视频中每帧提取出来,然后保存为图片。网上普遍有两种方法,第一种是通过opencv自带cvCvtColor,但是这种方法有bug,得到的图片会泛白。第二种方法是公式法。

法一:opencv自带cvCvtColor

说明:这种方法会出现图片“泛白”,具体原因网上是说cvCvtColor这个函数左右协议不同,不太懂。

代码:

 

[cpp]  view plain  copy
 print ?
  1. void FileWriteFrames(){  
  2.     char *filename = "E:\\openCV\\zhang\\yuvSource\\football_cif.yuv";  
  3.     ifstream readMe(filename, ios::in | ios::binary);  // 打开并读yuv数据  
  4.     IplImage *image, *rgbimg, *yimg, *uimg, *vimg, *uuimg, *vvimg;  
  5.     cvNamedWindow("yuv",CV_WINDOW_AUTOSIZE);  
  6.     rgbimg = cvCreateImage(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 3);  
  7.     image = cvCreateImage(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 3);  
  8.       
  9.     yimg = cvCreateImageHeader(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 1);    // 亮度分量  
  10.     uimg = cvCreateImageHeader(cvSize(ISizeX/2, ISizeY/2), IPL_DEPTH_8U, 1);  // 这两个都是色度分量  
  11.     vimg = cvCreateImageHeader(cvSize(ISizeX/2, ISizeY/2), IPL_DEPTH_8U, 1);  
  12.       
  13.     uuimg = cvCreateImage(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 1);  
  14.     vvimg = cvCreateImage(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 1);  
  15.     int nframes;  
  16.     for(nframes = 0; nframes < FCount; nframes ++){  
  17.         char nframesstr[20];  
  18.         readMe.read((char*)Y[nframes],ISizeX*ISizeY);  
  19.         //readMe.seekg(-ISizeX*ISizeY, ios::cur);  
  20.         //readMe.read((char*)buf[nframes],ISizeX*ISizeY+ISizeX/2*ISizeY/2+ISizeX/2*ISizeY/2);  
  21.         readMe.read((char*)buf[nframes],ISizeX/2*ISizeY/2);  
  22.         readMe.read((char*)buf2[nframes],ISizeX/2*ISizeY/2);  
  23.         cvSetData(yimg,Y[nframes],ISizeX);  
  24.         //cvSetData(uimg,buf[nframes] + ISizeX*ISizeY, ISizeX/2);  
  25.         cvSetData(uimg,buf[nframes], ISizeX/2);  
  26.         cvSetData(vimg,buf2[nframes], ISizeX/2);  
  27.   
  28.           
  29.         cvResize(uimg,uuimg, CV_INTER_LINEAR);  
  30.         cvResize(vimg,vvimg, CV_INTER_LINEAR);  
  31.         cvMerge(yimg,uuimg,vvimg,NULL,image);   // 合并单通道为三通道  
  32.         cvCvtColor(image,rgbimg,CV_YUV2BGR);      
  33.           
  34.         stringstream ss;  // 类型转换统一转换为char* 类型  
  35.         ss << nframes;  
  36.         ss << ".jpg" ;  
  37.         ss >> nframesstr;  
  38.         cvShowImage("yuv", rgbimg);  
  39.         cvSaveImage(nframesstr,rgbimg);  
  40.         int c = cvWaitKey(30);  
  41.         if((char)c == 27)  
  42.         {  
  43.             break;  
  44.         }  
  45.     }  
  46.     readMe.close();  
  47.     cvReleaseImage(&uuimg);  
  48.     cvReleaseImage(&vvimg);  
  49.     cvReleaseImageHeader(&yimg);  
  50.     cvReleaseImageHeader(&uimg);  
  51.     cvReleaseImageHeader(&vimg);  
  52.     cvReleaseImage(&image);  
  53.     cvDestroyWindow("yuv");   
  54. }  

法二:公式法

代码:

[cpp]  view plain  copy
 print ?
  1. bool YUV420_To_BGR24(unsigned char *puc_y, unsigned char *puc_u, unsigned char *puc_v, unsigned char *puc_rgb, int width_y, int height_y)  
  2. {  
  3.     if (!puc_y || !puc_u || !puc_v || !puc_rgb)  
  4.     {  
  5.         return false;  
  6.     }  
  7.       
  8.     //初始化变量  
  9.     int baseSize = width_y * height_y;  
  10.     int rgbSize = baseSize * 3;  
  11.   
  12.     BYTE* rgbData  = new BYTE[rgbSize];  
  13.     memset(rgbData, 0, rgbSize);  
  14.   
  15.     /* 变量声明 */  
  16.     int temp = 0;  
  17.   
  18.     BYTE* rData = rgbData;                  //r分量地址  
  19.     BYTE* gData = rgbData + baseSize;       //g分量地址  
  20.     BYTE* bData = gData   + baseSize;       //b分量地址  
  21.   
  22.     int uvIndex =0, yIndex =0;  
  23.   
  24.     //YUV->RGB 的转换矩阵  
  25.     //double  Yuv2Rgb[3][3] = {1, 0, 1.4022,  
  26.     //    1, -0.3456, -0.7145,  
  27.     //    1, 1.771,   0};  
  28.   
  29.     for(int y=0; y < height_y; y++)  
  30.     {  
  31.         for(int x=0; x < width_y; x++)  
  32.         {  
  33.             uvIndex        = (y>>1) * (width_y>>1) + (x>>1);  
  34.             yIndex         = y * width_y + x;  
  35.   
  36.             /* r分量 */  
  37.             temp          = (int)(puc_y[yIndex] + (puc_v[uvIndex] - 128) * 1.4022);  
  38.             rData[yIndex] = temp<0 ? 0 : (temp > 255 ? 255 : temp);  
  39.   
  40.             /* g分量 */  
  41.             temp          = (int)(puc_y[yIndex] + (puc_u[uvIndex] - 128) * (-0.3456) +  
  42.                 (puc_v[uvIndex] - 128) * (-0.7145));  
  43.             gData[yIndex] = temp < 0 ? 0 : (temp > 255 ? 255 : temp);  
  44.   
  45.             /* b分量 */  
  46.             temp          = (int)(puc_y[yIndex] + (puc_u[uvIndex] - 128) * 1.771);  
  47.             bData[yIndex] = temp < 0 ? 0 : (temp > 255 ? 255 : temp);  
  48.         }  
  49.     }  
  50.   
  51.     //将R,G,B三个分量赋给img_data  
  52.     int widthStep = width_y*3;  
  53.     for (int y = 0; y < height_y; y++)  
  54.     {  
  55.         for (int x = 0; x < width_y; x++)  
  56.         {  
  57.             puc_rgb[y * widthStep + x * 3 + 2] = rData[y * width_y + x];   //R  
  58.             puc_rgb[y * widthStep + x * 3 + 1] = gData[y * width_y + x];   //G  
  59.             puc_rgb[y * widthStep + x * 3 + 0] = bData[y * width_y + x];   //B  
  60.         }  
  61.     }  
  62.   
  63.     if (!puc_rgb)  
  64.     {  
  65.         return false;  
  66.     }  
  67.     delete [] rgbData;  
  68.     return true;  
  69. }  
  70.   
  71. IplImage* YUV420_To_IplImage(unsigned char* pYUV420, int width, int height)  
  72. {  
  73.     if (!pYUV420)  
  74.     {  
  75.         return NULL;  
  76.     }  
  77.   
  78.     //初始化变量  
  79.     int baseSize = width*height;  
  80.     int imgSize = baseSize*3;  
  81.     BYTE* pRGB24  = new BYTE[imgSize];  
  82.     memset(pRGB24,  0, imgSize);  
  83.   
  84.     /* 变量声明 */  
  85.     int temp = 0;  
  86.   
  87.     BYTE* yData = pYUV420;                  //y分量地址  
  88.     BYTE* uData = pYUV420 + baseSize;       //u分量地址  
  89.     BYTE* vData = uData  + (baseSize>>2);   //v分量地址  
  90.   
  91.     if(YUV420_To_BGR24(yData, uData, vData, pRGB24, width, height) == false || !pRGB24)  
  92.     {  
  93.         return NULL;  
  94.     }  
  95.   
  96.     IplImage *image = cvCreateImage(cvSize(width, height), 8,3);  
  97.     memcpy(image->imageData, pRGB24, imgSize);  
  98.   
  99.     if (!image)  
  100.     {  
  101.         return NULL;  
  102.     }  
  103.   
  104.     delete [] pRGB24;  
  105.     return image;  
  106. }  
  107.   
  108. void FileWriteFrames(){  
  109.     char *filename = "E:\\openCV\\zhang\\yuvSource\\FOOTBALL_352x288_30_orig_01.yuv";  
  110.     ifstream readMe(filename, ios::in | ios::binary);  // 打开并读yuv数据  
  111.     int nframes;  
  112.     for(nframes = 0; nframes < FCount; nframes ++){  
  113.         char nframesstr[20];  
  114.         readMe.read((char*)Y[nframes],ISizeX*ISizeY);  
  115.         readMe.seekg(-ISizeX*ISizeY, ios::cur);  
  116.         readMe.read((char*)buf[nframes],ISizeX*ISizeY+ISizeX/2*ISizeY/2+ISizeX/2*ISizeY/2);    
  117.         IplImage *rgbimg = YUV420_To_IplImage(buf[nframes], ISizeX, ISizeY);  
  118.         stringstream ss;  // 类型转换统一转换为char* 类型  
  119.         ss << nframes;  
  120.         ss << ".jpg" ;  
  121.         ss >> nframesstr;  
  122.         cvShowImage("yuv", rgbimg);  
  123.         cvSaveImage(nframesstr,rgbimg);  
  124.         int c = cvWaitKey(30);  
  125.         if((char)c == 27)  
  126.         {  
  127.             break;  
  128.         }  
  129.     }  
  130.     readMe.close();  
  131. }  

完整代码见:http://download.csdn.net/detail/lu597203933/7362687

参见blog:http://blog.csdn.net/dreamd1987/article/details/7259479#

你可能感兴趣的:(opencv学习笔记,YUV,BGR,opencv)