opencvに基づいてYUV画像をRGB画像に変換します

YUV2RGB形式変換

       最近アームボード上のプロジェクトに取り組んでいるのですが、アームボードに収集された画像はYUV形式であり、その後の画像処理ではRGB形式の画像が必要になります。インターネット上で YUV から RGB への情報をたくさん調べましたが、入手できる YUV データの配置形式は人によって異なるため、プロジェクトに適したコードを見つけるのは簡単ではありません。その中でも、2つのブログの情報がとても刺激になったので、ここで紹介させていただきます。URLは次のとおりです。

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

2.  http://blog.csdn.net/Lu597203933/article/details/23791177


インターネットには通常 2 つの方法があります。 1. opencv に付属の cvCvtColor 関数を使用して変換します2. 計算方法。

1.opencv には cvCvtColor が付属しています

テストデータをファイルに送信して質問することができます(他の人のテストデータもダウンロードします)

テストファイル名:football_cif.yuv、FOOTBALL_352x288_30_orig_01.yuv

画像サイズ:352*288

これら 2 つのファイルのデータ ストレージ形式は次のとおりです。 YUV、つまり、最初にすべての Y を格納し、次にすべての U を格納し、最後にすべての V を格納します (非インターリーブ ストレージ)。

具体的なコードは次のとおりです。

#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. 計算方法

テストデータ: test1.bmp、test2.bmp (必要に応じて、メッセージを残して電子メールを残してください)

データ保存形式:UYVY(インターリーブストレージ)

画像サイズ:1024*480

テストコードは次のとおりです。

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



おすすめ

転載: blog.csdn.net/beijingmake209/article/details/42124741