转自:http://www.cnblogs.com/tingshuo/archive/2011/05/13/2045649.html
想在流媒体领域走的更远一点,但是发现自己这方面的专业知识欠缺厉害,特别是图形图像专业知识,于是买了本《数字图像处理》补补。这本书纯理论,什么积分、微分、什么滤波器,傅立叶变换,搞得一头雾水,还是写几行代码来得踏实。
言归正题,图像缩放顾名思义,就是把原图像按照目标尺寸放大或者缩小,是图像处理的一种。自然,图像缩放的核心也就是怎么样根据已知图像计算目标图像的各点像素值。最简单的是最临近插值算法,这种算法就是根据原图像和目标图像的尺寸,计算缩放的比例,然后根据缩放比例计算目标像素所依据的原像素,过程中自然会产生小数,这时就采用四舍五入,取与这个点最相近的点。另一种算法是双线性内插值算法,这种算法的目标像素值不再简单地由一个像素决定,而是由他的四临域乘以相应的权重决定。具体公式为:
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
其中U和V是浮点坐标的小数部分,显然离目标点距离越近的点的权重越大,这也正符合目标点的值与离他最近的点最接近这一事实。关于这两种算法的详细说明,网上很多,这里就不多说了。下面是实现程序,这里除了两个算法之外,还涉及到位图的读写操作。具体看注释吧,需要注意的是位图中有涉及到调色板,这里为了简便,原图像最好是不带有调色板的24位位图。
1
#include
"
stdafx.h
"
2
#include
<
stdio.h
>
3
#include
<
string
>
4
#include
<
windows.h
>
5
using
namespace
std;
6
7
enum
StretchMode
8
{
9
nearest,
//
最临近插值算法
10
bilinear
//
双线性内插值算法
11
};
12
13
void
Stretch(
const
string
&
srcFile,
const
string
&
desFile,
int
desW,
int
desH,StretchMode mode)
14
{
15
BITMAPFILEHEADER bmfHeader;
16
BITMAPINFOHEADER bmiHeader;
17
18
FILE
*
pFile;
19
if
((pFile
=
fopen(srcFile.c_str(),
"
rb
"
))
==
NULL)
20
{
21
printf(
"
open bmp file error.
"
);
22
exit(
-
1
);
23
}
24
//
读取文件和Bitmap头信息
25
fseek(pFile,
0
,SEEK_SET);
26
fread(
&
bmfHeader,
sizeof
(BITMAPFILEHEADER),
1
,pFile);
27
fread(
&
bmiHeader,
sizeof
(BITMAPINFOHEADER),
1
,pFile);
28
//
先不支持小于16位的位图
29
int
bitCount
=
bmiHeader.biBitCount;
30
if
(bitCount
<
16
)
31
{
32
exit(
-
1
);
33
}
34
int
srcW
=
bmiHeader.biWidth;
35
int
srcH
=
bmiHeader.biHeight;
36
37
int
lineSize
=
bitCount
*
srcW
/
8
;
38
//
偏移量,windows系统要求每个扫描行按四字节对齐
39
int
alignBytes
=
((bmiHeader.biWidth
*
bitCount
+
31
)
&
~
31
)
/
8L
40
-
bmiHeader.biWidth
*
bitCount
/
8L
;
41
//
原图像缓存
42
int
srcBufSize
=
lineSize
*
srcH;
43
BYTE
*
srcBuf
=
new
BYTE[srcBufSize];
44
int
i,j;
45
//
读取文件中数据
46
for
(i
=
0
; i
<
srcH; i
++
)
47
{
48
fread(
&
srcBuf[lineSize
*
i],lineSize,
1
,pFile);
49
fseek(pFile,alignBytes,SEEK_CUR);
50
}
51
52
//
目标图像缓存
53
int
desBufSize
=
((desW
*
bitCount
+
31
)
/
32
)
*
4
*
desH;
54
int
desLineSize
=
((desW
*
bitCount
+
31
)
/
32
)
*
4
;
55
BYTE
*
desBuf
=
new
BYTE[desBufSize];
56
double
rateH
=
(
double
)srcH
/
desH;
57
double
rateW
=
(
double
)srcW
/
desW;
58
//
最临近插值算法
59
if
(mode
==
nearest)
60
{
61
for
(i
=
0
; i
<
desH; i
++
)
62
{
63
//
选取最邻近的点
64
int
tSrcH
=
(
int
)(rateH
*
i
+
0.5
);
65
for
(j
=
0
; j
<
desW; j
++
)
66
{
67
int
tSrcW
=
(
int
)(rateW
*
j
+
0.5
);
68
memcpy(
&
desBuf[i
*
desLineSize]
+
j
*
bmiHeader.biBitCount
/
8
,
&
srcBuf[tSrcH
*
lineSize]
+
tSrcW
*
bmiHeader.biBitCount
/
8
,bmiHeader.biBitCount
/
8
);
69
}
70
}
71
}
72
//
双线型内插值算法
73
else
74
{
75
for
(i
=
0
; i
<
desH; i
++
)
76
{
77
int
tH
=
(
int
)(rateH
*
i);
78
int
tH1
=
min(tH
+
1
,srcH
-
1
);
79
float
u
=
(
float
)(rateH
*
i
-
tH);
80
for
(j
=
0
; j
<
desW; j
++
)
81
{
82
int
tW
=
(
int
)(rateW
*
j);
83
int
tW1
=
min(tW
+
1
,srcW
-
1
);
84
float
v
=
(
float
)(rateW
*
j
-
tW);
85
86
//
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
87
for
(
int
k
=
0
; k
<
3
; k
++
)
88
{
89
desBuf[i
*
desLineSize
+
j
*
bitCount
/
8
+
k]
=
90
(
1
-
u)
*
(
1
-
v)
*
srcBuf[tH
*
lineSize
+
tW
*
bitCount
/
8
+
k]
+
91
(
1
-
u)
*
v
*
srcBuf[tH1
*
lineSize
+
tW
*
bitCount
/
8
+
k]
+
92
u
*
(
1
-
v)
*
srcBuf[tH
*
lineSize
+
tW1
*
bitCount
/
8
+
k]
+
93
u
*
v
*
srcBuf[tH1
*
lineSize
+
tW1
*
bitCount
/
8
+
k];
94
}
95
}
96
}
97
}
98
99
//
创建目标文件
100
HFILE hfile
=
_lcreat(desFile.c_str(),
0
);
101
//
文件头信息
102
BITMAPFILEHEADER nbmfHeader;
103
nbmfHeader.bfType
=
0x4D42
;
104
nbmfHeader.bfSize
=
sizeof
(BITMAPFILEHEADER)
+
sizeof
(BITMAPINFOHEADER)
105
+
desW
*
desH
*
bitCount
/
8
;
106
nbmfHeader.bfReserved1
=
0
;
107
nbmfHeader.bfReserved2
=
0
;
108
nbmfHeader.bfOffBits
=
sizeof
(BITMAPFILEHEADER)
+
sizeof
(BITMAPINFOHEADER);
109
//
Bitmap头信息
110
BITMAPINFOHEADER bmi;
111
bmi.biSize
=
sizeof
(BITMAPINFOHEADER);
112
bmi.biWidth
=
desW;
113
bmi.biHeight
=
desH;
114
bmi.biPlanes
=
1
;
115
bmi.biBitCount
=
bitCount;
116
bmi.biCompression
=
BI_RGB;
117
bmi.biSizeImage
=
0
;
118
bmi.biXPelsPerMeter
=
0
;
119
bmi.biYPelsPerMeter
=
0
;
120
bmi.biClrUsed
=
0
;
121
bmi.biClrImportant
=
0
;
122
123
//
写入文件头信息
124
_lwrite(hfile,(LPCSTR)
&
nbmfHeader,
sizeof
(BITMAPFILEHEADER));
125
//
写入Bitmap头信息
126
_lwrite(hfile,(LPCSTR)
&
bmi,
sizeof
(BITMAPINFOHEADER));
127
//
写入图像数据
128
_lwrite(hfile,(LPCSTR)desBuf,desBufSize);
129
_lclose(hfile);
130
}
131
132
int
main(
int
argc,
char
*
argv[])
133
{
134
FILE
*
pFile;
135
if
((pFile
=
fopen(
"
e://t.bmp
"
,
"
rb
"
))
==
NULL)
136
{
137
printf(
"
open bmp file error.
"
);
138
return
-
1
;
139
}
140
string
srcFile(
"
e://t.bmp
"
);
141
string
desFileN(
"
e://nearest.bmp
"
);
142
string
desFileB(
"
e://bilinear.bmp
"
);
143
Stretch(srcFile,desFileN,
800
,
600
,nearest);
144
Stretch(srcFile,desFileB,
800
,
600
,bilinear);
145
//
int alignBytes = ~31;
146
//
printf("alignbytes : %d",alignBytes);
147
148
system(
"
pause
"
);
149
return
0
;
150
}
结论:通过生成的两幅图像对比,双线性内插值算法缩放效果比最邻近插值算法好很多。