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
);
}
};
【数字图像处理】YUV420转RGB并BMP存储<纯C++实现>
最新推荐文章于 2023-05-24 19:52:49 发布