【数字图像处理】YUV420转RGB并BMP存储<纯C++实现>

  
  
1、读取akiyo_qcif.yuv YUV420文件,按帧读取,转RGB,并存储到BMP文件。
2、暂时实现读取一帧并存储一张BMP图片。 若要读取YUV序列,写成循环方式即可。
3、生成的BMP文件还有一点小问题:图像的倒立的,而且红色偏多。
YUV是qcif分辨率。
估计是YUV到RGB的计算公式有点问题。解决中。。。。
图像倒立问题已经解决。
红色不知道是不是公式变换和RGB数值区间限制的时候产生的。估计和UV的差值方式也有关系。
红色的问题已经解决,采用的变换公式不正确。 但是还是有一些横纹,不知道是怎么回事。
 
     
     
头文件 Ex1 . h
typedef unsigned char BYTE ;
typedef unsigned short WORD ;
typedef unsigned int DWORD ;
typedef long LONG ;
//位图文件头定义;
//其中不包含文件类型信息(由于结构体的内存结构决定,
//要是加了的话将不能正确读取文件信息)
typedef struct tagBITMAPFILEHEADER {
// WORD bfType;//文件类型,必须是0x424D,即字符“BM”
DWORD bfSize ; //文件大小
WORD bfReserved1 ; //保留字
WORD bfReserved2 ; //保留字
DWORD bfOffBits ; //从文件头到实际位图数据的偏移字节数
} BITMAPFILEHEADER ;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize ; //信息头大小
LONG biWidth ; //图像宽度
LONG biHeight ; //图像高度
WORD biPlanes ; //位平面数,必须为1
WORD biBitCount ; //每像素位数
DWORD biCompression ; //压缩类型
DWORD biSizeImage ; //压缩图像大小字节数
LONG biXPelsPerMeter ; //水平分辨率
LONG biYPelsPerMeter ; //垂直分辨率
DWORD biClrUsed ; //位图实际用到的色彩数
DWORD biClrImportant ; //本位图中重要的色彩数
} BITMAPINFOHEADER ; //位图信息头定义
typedef struct tagRGBQUAD {
BYTE rgbBlue ; //该颜色的蓝色分量
BYTE rgbGreen ; //该颜色的绿色分量
BYTE rgbRed ; //该颜色的红色分量
BYTE rgbReserved ; //保留值
} RGBQUAD ; //调色板定义
//像素信息
typedef struct tagIMAGEDATA
{
BYTE blue ; ///8位灰度图用其中1个
BYTE green ;
BYTE red ;
} IMAGEDATA ;
源文件 Ex1 . cpp
#include "stdafx.h"
#include "Ex1.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <iostream.h>
#define qcif
#ifdef qcif
#define Y_WIDTH 176
#define Y_HEIGHT 144
#define U_WIDTH 88
#define U_HEIGHT 72
#define V_WIDTH 88
#define V_HEIGHT 72
#endif
//变量定义
BITMAPFILEHEADER strHead ; //位图文件头
BITMAPINFOHEADER strInfo ; //位图信息头
unsigned char Y_space [ Y_WIDTH * Y_HEIGHT ];
unsigned char U_space [ U_WIDTH * U_HEIGHT ];
unsigned char V_space [ V_WIDTH * V_HEIGHT ];
unsigned char R_space [ Y_WIDTH * Y_HEIGHT ];
unsigned char G_space [ Y_WIDTH * Y_HEIGHT ];
unsigned char B_space [ Y_WIDTH * Y_HEIGHT ];
void ReadImage ( unsigned char * pImage , char * cFileName , int nWidth , int nHeight , long offset ); 读取YUV文件
int main ( int argc , char * argv [])
{
long origin = 0 + Y_WIDTH * Y_HEIGHT + U_WIDTH * U_HEIGHT + V_WIDTH * V_HEIGHT ; ///YUV文件起始位置
int i , j , u_j , v_j ;
int width , height ;
width = Y_WIDTH ;
height = Y_HEIGHT ;
FILE * fpw ;
WORD bfType_w = 0x4d42 ;
IMAGEDATA * imagedata = NULL ; //动态分配存储BMP图片的像素信息的二维数组
imagedata = ( IMAGEDATA * ) malloc ( width * height * sizeof ( IMAGEDATA )); //按IMAGEDATA结构体大小,分配存储BMP图片的存储空间
//初始化原始图片的像素数组
for ( i = 0 ; i < height ; ++ i )
{
for ( int j = 0 ; j < width ; ++ j )
{
( * ( imagedata + i * width + j )). blue = 0 ;
( * ( imagedata + i * width + j )). green = 0 ;
( * ( imagedata + i * width + j )). red = 0 ;
}
}
// origin=0;///读第一帧
// for(i=0,origin=0;i<148;i++,origin+=(Y_WIDTH*Y_HEIGHT+U_WIDTH*U_HEIGHT+V_WIDTH*V_HEIGHT))
// {///读取第一帧图像
ReadImage ( Y_space , "akiyo_qcif.yuv" , Y_WIDTH , Y_HEIGHT , origin ); //carphone001.yuv
ReadImage ( V_space , "akiyo_qcif.yuv" , V_WIDTH , V_HEIGHT , Y_WIDTH * Y_HEIGHT ); ///读取方法涉及YUV的存储顺序。 存储顺序是所有Y,随后是所有V,最后是所有U。
ReadImage ( U_space , "akiyo_qcif.yuv" , U_WIDTH , U_HEIGHT , Y_WIDTH * Y_HEIGHT + V_WIDTH * V_HEIGHT );
// }
///YUV转成RGB 176*144 88*72 width * height
u_j = 0 ; v_j = 0 ;
int y , cb , cr ; //y u v
int r , g , b ;
for ( i = 0 ; i < Y_HEIGHT ; i ++ )
{
for ( j = 0 ; j < Y_WIDTH ; j ++ )
{
u_j = j / 2 ; ///取倍数
v_j = j / 2 ; ///取倍数,U和V的宽度是Y的一半。
/对应4:2:0 YUV 采样方式 参考文章:http://blog.csdn.net/shallon_luo/article/details/5544796
y = Y_space [ j + i * Y_WIDTH ];
cb = U_space [ u_j + i * U_WIDTH ];
cr = V_space [ v_j + i * V_WIDTH ];
/* R = Y + 1.14V,G = Y - 0.39U - 0.58V,B = Y + 2.03U YUV对应YCbCr
r = y + 1.14*cr;
g = y - 0.39*cb - 0.58*cr;
b = y + 2.03*cb; */
/* YCbCr与RGB的关系 */
r = 1.164 * ( y - 16 ) + 1.596 * ( cr - 128 );
g = 1.164 * ( y - 16 ) - 0.813 * ( cr - 128 ) - 0.392 * ( cb - 128 );
b = 1.164 * ( y - 16 ) + 2.017 * ( cb - 128 );
/* r=1.0*y+1.402*(cr-128) ;
g=1.0*y-0.34413*(cb-128)-0.71414*(cr-128);
b=1.0*y+1.772*(cb-128);*/
r = r > 255 ? 255 : r ;
g = g > 255 ? 255 : g ;
b = b > 255 ? 255 : b ;
r = r < 0 ? 0 : r ;
g = g < 0 ? 0 : g ;
b = b < 0 ? 0 : b ;
B_space [ j + i * Y_WIDTH ] = b ;
G_space [ j + i * Y_WIDTH ] = g ;
R_space [ j + i * Y_WIDTH ] = r ;
}
}
for ( i = 0 ; i < Y_HEIGHT ; ++ i )
{
for ( int j = 0 ; j < Y_WIDTH ; ++ j )
{
( * ( imagedata + i * Y_WIDTH + j )). blue = B_space [ j + i * Y_WIDTH ];
( * ( imagedata + i * Y_WIDTH + j )). green = G_space [ j + i * Y_WIDTH ];
( * ( imagedata + i * Y_WIDTH + j )). red = R_space [ j + i * Y_WIDTH ];
}
}
///保存BMP图像
if (( fpw = fopen ( "result033.bmp" , "wb" )) == NULL )
{
cout << "create the bmp file error!" << endl ;
return NULL ;
}
fwrite ( & bfType_w , 1 , sizeof ( WORD ), fpw );
strHead . bfSize = Y_WIDTH * Y_HEIGHT * 3 + 54 ; //位图文件大小,说明文件的大小,用字节为单位
strHead . bfReserved1 = 0 ;
strHead . bfReserved2 = 0 ;
strHead . bfOffBits = 54 ; //从文件头到实际位图数据的偏移字节数14+40,无调色板。
fwrite ( & strHead , 1 , sizeof ( tagBITMAPFILEHEADER ), fpw );
strInfo . biWidth = Y_WIDTH ; //指定图象的宽度,单位是象素。
strInfo . biHeight = Y_HEIGHT ; //指定图象的高度,单位是象素。
strInfo . biBitCount = 24 ; 指定表示颜色时要用到的位数,常用的值为1(黑白二色图), 4(16色图), 8(256色), 24(真彩色图)(
strInfo . biClrImportant = 0 ; ///指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。
strInfo . biClrUsed = 0 ; ///指定本图象实际用到的颜色数,如果该值为零,则用到的颜色数为2的biBitCount次方。
strInfo . biCompression = 0 ; //指定位图是否压缩。
strInfo . biPlanes = 1 ; ///平面数,必须是1
strInfo . biSize = 40 ; ///指定这个结构的长度,必须是40。
strInfo . biSizeImage = 3 * width * height ; //指定实际的位图数据占用的字节数,似乎填什么都可以。
fwrite ( & strInfo , 1 , sizeof ( tagBITMAPINFOHEADER ), fpw );
//保存像素数据
for ( i = Y_HEIGHT ; i > 0 ; -- i ) ///从上往下写。图像上下翻转
{
for ( int j = 0 ; j < Y_WIDTH ; ++ j )
//for(int j = Y_WIDTH;j > 0;--j)///从右往左写 图像左右对调
{
fwrite ( & (( * ( imagedata + i * Y_WIDTH + j )). blue ), 1 , sizeof ( BYTE ), fpw );
fwrite ( & (( * ( imagedata + i * Y_WIDTH + j )). green ), 1 , sizeof ( BYTE ), fpw );
fwrite ( & (( * ( imagedata + i * Y_WIDTH + j )). red ), 1 , sizeof ( BYTE ), fpw );
}
}
fclose ( fpw );
//释放内存
delete [] imagedata ;
return 0 ;
}
void ReadImage ( unsigned char * pImage , char * cFileName , int nWidth , int nHeight , long offset )
{
int j , i ;
unsigned char * pWork ;
FILE * fp = 0 ;
if ( fp = fopen ( cFileName , "rb" ) ) //打开一幅图像
{
fseek ( fp , offset , SEEK_SET ); //文件定位
pWork = pImage ; //指针指向
for ( j = 0 ; j < nHeight ; j ++ , pWork += nWidth )
for ( i = 0 ; i < nWidth ; i ++ )
fread ( pWork + i , 1 , 1 , fp ); //顺序读取,每次读一个字节存入pwork[]中
fclose ( fp );
}
};
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值