conversão de formato YUV2RGB
Recentemente, trabalhei em um projeto na placa de braço.As imagens coletadas na placa de braço estão no formato YUV e as imagens no formato RGB são necessárias no processamento subsequente da imagem. Eu verifiquei muitas informações de YUV para RGB na Internet. Como o formato de arranjo de dados YUV que cada um obtém é diferente, não é fácil encontrar o código adequado ao seu projeto. Entre eles, as informações de dois blogs me inspiraram muito, e vou apresentá-los aqui para vocês. A URL é a seguinte:
1. http://blog.csdn.net/dreamd1987/article/details/7259479#
2. http://blog.csdn.net/Lu597203933/article/details/23791177
Geralmente, existem dois métodos na Internet: 1. Converta por meio da função cvCvtColor que vem com o opencv . 2. Método de fórmula.
1. opencv vem com cvCvtColor
Os dados de teste podem ser enviados para o arquivo para me perguntar (eu também baixo os dados de teste de outras pessoas)
Nome do arquivo de teste: football_cif.yuv, FOOTBALL_352x288_30_orig_01.yuv
Tamanho da imagem: 352*288
O formato de armazenamento de dados desses dois arquivos é: YUV, ou seja, armazena todo o Y primeiro, depois armazena todo o U e, finalmente, armazena todo o V (armazenamento não intercalado)
O código específico é o seguinte:
#include <iostream>
#include <highgui.h>
#include <cv.h>
#include <fstream>
#include <sstream>
using namespace std;
#define FCount 10
#define ISizeX 352 //图像宽度
#define ISizeY 288 //图像高度
unsigned char Y[FCount][ISizeY][ISizeX];
unsigned char U[FCount][ISizeY/2][ISizeX/2];
unsigned char V[FCount][ISizeY/2][ISizeX/2];
// 将图片文件写入
void FileWriteFrames()
{
char *filename = "football_cif.yuv";
ifstream readMe(filename, ios::in | ios::binary); // 打开并读yuv数据
IplImage *image, *rgbimg, *yimg, *uimg, *vimg, *uuimg, *vvimg;
cvNamedWindow("yuv",CV_WINDOW_AUTOSIZE);
rgbimg = cvCreateImage(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 3);
image = cvCreateImage(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 3);
yimg = cvCreateImageHeader(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 1); // 亮度分量
uimg = cvCreateImageHeader(cvSize(ISizeX/2, ISizeY/2), IPL_DEPTH_8U, 1); // 这两个都是色度分量
vimg = cvCreateImageHeader(cvSize(ISizeX/2, ISizeY/2), IPL_DEPTH_8U, 1);
uuimg = cvCreateImage(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 1);
vvimg = cvCreateImage(cvSize(ISizeX, ISizeY), IPL_DEPTH_8U, 1);
int nframes;
for(nframes = 0; nframes < FCount; nframes ++)
{
char nframesstr[20];
readMe.read((char*)Y[nframes],ISizeX*ISizeY); //读取Y分量
readMe.read((char*)U[nframes],ISizeX/2*ISizeY/2);//读取U分量
readMe.read((char*)V[nframes],ISizeX/2*ISizeY/2);//读取V分量
cvSetData(yimg,Y[nframes],ISizeX);
cvSetData(uimg,U[nframes], ISizeX/2);
cvSetData(vimg,V[nframes], ISizeX/2);
cvResize(uimg,uuimg, CV_INTER_LINEAR);
cvResize(vimg,vvimg, CV_INTER_LINEAR);
cvMerge(yimg,uuimg,vvimg,NULL,image); // 合并单通道为三通道
cvCvtColor(image,rgbimg,CV_YCrCb2RGB); // YUV转换为RGB
stringstream ss; // 类型转换统一转换为char* 类型
ss << nframes;
ss << ".jpg" ;
ss >> nframesstr;
cvShowImage("yuv", rgbimg);
cvSaveImage(nframesstr,rgbimg);
int c = cvWaitKey(300);
if((char)c == 27)
{
break;
}
}
readMe.close();
cvReleaseImage(&uuimg);
<span style="white-space:pre"> </span>cvReleaseImage(&vvimg);
cvReleaseImageHeader(&yimg);
cvReleaseImageHeader(&uimg);
cvReleaseImageHeader(&vimg);
cvReleaseImage(&image);
cvDestroyWindow("yuv");
}
int main()
{
FileWriteFrames();
return 0;
}
2. Método de fórmula
Dados do teste: test1.bmp, test2.bmp (se necessário, você pode me deixar uma mensagem e deixar seu e-mail)
Formato de armazenamento de dados: UYVY (armazenamento intercalado)
Tamanho da imagem: 1024*480
O código de teste é o seguinte:
#include <iostream>
#include <highgui.h>
#include <cv.h>
#include <fstream>
#include <sstream>
using namespace std;
#define width 1024 //图像宽度
#define height 480 //图像高度
unsigned char *yuvtorgb24(char *bufyuv, int w, int h)
{
int r1,g1,b1,r2,g2,b2;
int y1,u,v,y2;
unsigned char *ps=(unsigned char *)bufyuv;
unsigned char *pd;
int len;
if ((pd = (unsigned char *)malloc (w * h * 3)) == NULL)
return NULL;
len=w*h;
while(len>0)
{
len-=2;
u=*ps++;
y1 =*ps++;
v=*ps++;
y2 =*ps++;
r1=(10000*y1+14075*(v-128))/10000;
g1=(10000*y1-3455*(u-128)-7169*(v-128))/10000;
b1=(10000*y1+17990*(u-128))/10000;
r2=(10000*y2+14075*(v-128))/10000;
g2=(10000*y2-3455*(u-128)-7169*(v-128))/10000;
b2=(10000*y2+17990*(u-128))/10000;
if(r1>255)r1=255;if(r1<0)r1=0;
if(g1>255)g1=255;if(g1<0)g1=0;
if(b1>255)b1=255;if(b1<0)b1=0;
if(r2>255)r2=255;if(r2<0)r2=0;
if(g2>255)g2=255;if(g2<0)g2=0;
if(b2>255)b2=255;if(b2<0)b2=0;
*pd++=b1;*pd++=g1;*pd++=r1;
*pd++=b2;*pd++=g2;*pd++=r2;
}
return pd-(w*h*3);
}
int main()
{
int i, j;
unsigned char *p;
char recvBuf[width*height*2];
IplImage *srcImg;
char *filename = "test2.bmp";
srcImg = cvCreateImage(cvSize(width, height), 8, 3);
cvZero(srcImg);
ifstream fin(filename, ios::in | ios::binary); // 打开并读yuv数据
fin.read(recvBuf, width*height*2*sizeof(char));
/* 查看数据
for(i=0; i<500; i++)
{
unsigned char tmp = (unsigned char)recvBuf[i];
cout<< (unsigned short)tmp<<endl;
}
*/
// yuv格式转换为rgb格式
p = yuvtorgb24(recvBuf, 1024, 480);
// 图像颜色赋值
for(i=0; i<height; i++)
{
for(j=0; j<width; j++)
{
((uchar *)(srcImg->imageData + i*srcImg->widthStep))[j*srcImg->nChannels + 0] = p[(i*width+j)*3 + 0];
((uchar *)(srcImg->imageData + i*srcImg->widthStep))[j*srcImg->nChannels + 1] = p[(i*width+j)*3 + 1];
((uchar *)(srcImg->imageData + i*srcImg->widthStep))[j*srcImg->nChannels + 2] = p[(i*width+j)*3 + 2];
}
}
free(p);
cvSaveImage("mytest2.bmp", srcImg);
cvNamedWindow("YUV2RGB", 1);
cvShowImage("YUV2RGB", srcImg);
cvWaitKey(0);
cvReleaseImage(&srcImg);
return 0;
}