HouSisong@GMail.com 2008.04.22
tag: 误差扩散,真彩色到高彩色转换
摘要: 在图像的颜色转换过程中,由于颜色值域的不同,转换过程中可能会产生误差;
误差扩散算法通过将误差传递到周围像素而减轻其造成的视觉误差。
正文:
代码使用C++,编译器:VC2005
测试平台:(CPU:AMD64x2 4200+(2.37G); 内存:DDR2 677(双通道); 编译器:VC2005)
(请先参看文章的上篇)
E: 将误差扩散的浮点实现改写为一个整数的定点数实现:
struct
TErrorColor{
long
dR;
long
dG;
long
dB;
};
inline
long
getBestRGB16_555Color(
const
long
wantColor){
const
long
rMax
=
(
1
<<
5
)
-
1
;
if
(wantColor
<=
0
)
return
0
;
else
if
(wantColor
>=
(rMax
<<
3
))
return
rMax;
else
return
wantColor
>>
3
;
}
inline
long
getC8Color(
const
long
rColor){
return
rColor
*
(((
1
<<
16
)
*
255
+
30
)
/
31
)
>>
16
;
}
void
CvsPic32To16_ErrorDiffuse_Line_1(TUInt16
*
pDst,
const
TARGB32
*
pSrc,
long
width,TErrorColor
*
PHLineErr){
TErrorColor HErr;
HErr.dR
=
0
; HErr.dG
=
0
; HErr.dB
=
0
;
PHLineErr[
-
1
].dB
=
0
; PHLineErr[
-
1
].dG
=
0
; PHLineErr[
-
1
].dR
=
0
;
for
(
long
x
=
0
;x
<
width;
++
x)
{
long
cB
=
(pSrc[x].b
+
HErr.dB
*
2
+
PHLineErr[x].dB
+
PHLineErr[x
-
1
].dB);
long
cG
=
(pSrc[x].g
+
HErr.dG
*
2
+
PHLineErr[x].dG
+
PHLineErr[x
-
1
].dG);
long
cR
=
(pSrc[x].r
+
HErr.dR
*
2
+
PHLineErr[x].dR
+
PHLineErr[x
-
1
].dR);
long
rB
=
getBestRGB16_555Color(cB);
long
rG
=
getBestRGB16_555Color(cG);
long
rR
=
getBestRGB16_555Color(cR);
pDst[x]
=
rB
|
(rG
<<
5
)
|
(rR
<<
10
);
HErr.dB
=
(cB
-
getC8Color(rB))
>>
2
;
HErr.dG
=
(cG
-
getC8Color(rG))
>>
2
;
HErr.dR
=
(cR
-
getC8Color(rR))
>>
2
;
PHLineErr[x
-
1
].dB
+=
HErr.dB;
PHLineErr[x
-
1
].dG
+=
HErr.dG;
PHLineErr[x
-
1
].dR
+=
HErr.dR;
PHLineErr[x]
=
HErr;
}
}
void
CvsPic32To16_ErrorDiffuse_1(
const
TPicRegion_RGB16_555
&
dst,
const
TPicRegion
&
src){
TUInt16
*
pDst
=
(TUInt16
*
)dst.pdata;
const
TARGB32
*
pSrc
=
src.pdata;
const
long
width
=
src.width;
TErrorColor
*
_HLineErr
=
new
TErrorColor[width
+
2
];
for
(
long
x
=
0
;x
<
width
+
2
;
++
x){
_HLineErr[x].dR
=
0
;
_HLineErr[x].dG
=
0
;
_HLineErr[x].dB
=
0
;
}
TErrorColor
*
HLineErr
=&
_HLineErr[
1
];
for
(
long
y
=
0
;y
<
src.height;
++
y){
CvsPic32To16_ErrorDiffuse_Line_1(pDst,pSrc,width,HLineErr);
(TUInt8
*&
)pDst
+=
dst.byte_width;
(TUInt8
*&
)pSrc
+=
src.byte_width;
}
delete[]_HLineErr;
}
速度测试:
//////////////////////////////////////////////////////////////
//CvsPic32To16_ErrorDiffuse_1 154.4 FPS
//////////////////////////////////////////////////////////////
F:继续优化
getBestRGB16_555Color函数有条件分支,建立一个查找表来代替,完整的实现如下:
(CvsPic32To16_ErrorDiffuse_Line_2和CvsPic32To16_ErrorDiffuse_Line_1完成的功能一致)
static
TUInt8 _BestRGB16_555Color_Table[
256
*
5
];
const
TUInt8
*
BestRGB16_555Color_Table
=&
_BestRGB16_555Color_Table[
256
*
2
];
struct
_TAutoInit_BestRGB16_555Color_Table{
_TAutoInit_BestRGB16_555Color_Table(){
for
(
long
i
=
0
;i
<
256
*
5
;
++
i){
_BestRGB16_555Color_Table[i]
=
getBestRGB16_555Color(i
-
256
*
2
);
}
}
};
static
_TAutoInit_BestRGB16_555Color_Table _AutoInit_BestRGB16_555Color_Table;
void
CvsPic32To16_ErrorDiffuse_Line_2(TUInt16
*
pDst,
const
TARGB32
*
pSrc,
long
width,TErrorColor
*
PHLineErr){
TErrorColor HErr;
HErr.dR
=
0
; HErr.dG
=
0
; HErr.dB
=
0
;
PHLineErr[
-
1
].dB
=
0
; PHLineErr[
-
1
].dG
=
0
; PHLineErr[
-
1
].dR
=
0
;
for
(
long
x
=
0
;x
<
width;
++
x)
{
long
cB
=
(pSrc[x].b
+
HErr.dB
*
2
+
PHLineErr[x].dB
+
PHLineErr[x
-
1
].dB);
long
cG
=
(pSrc[x].g
+
HErr.dG
*
2
+
PHLineErr[x].dG
+
PHLineErr[x
-
1
].dG);
long
cR
=
(pSrc[x].r
+
HErr.dR
*
2
+
PHLineErr[x].dR
+
PHLineErr[x
-
1
].dR);
long
rB
=
BestRGB16_555Color_Table[cB];
long
rG
=
BestRGB16_555Color_Table[cG];
long
rR
=
BestRGB16_555Color_Table[cR];
pDst[x]
=
rB
|
(rG
<<
5
)
|
(rR
<<
10
);
HErr.dB
=
(cB
-
getC8Color(rB))
>>
2
;
HErr.dG
=
(cG
-
getC8Color(rG))
>>
2
;
HErr.dR
=
(cR
-
getC8Color(rR))
>>
2
;
PHLineErr[x
-
1
].dB
+=
HErr.dB;
PHLineErr[x
-
1
].dG
+=
HErr.dG;
PHLineErr[x
-
1
].dR
+=
HErr.dR;
PHLineErr[x]
=
HErr;
}
}
void
CvsPic32To16_ErrorDiffuse_2(
const
TPicRegion_RGB16_555
&
dst,
const
TPicRegion
&
src){
TUInt16
*
pDst
=
(TUInt16
*
)dst.pdata;
const
TARGB32
*
pSrc
=
src.pdata;
const
long
width
=
src.width;
TErrorColor
*
_HLineErr
=
new
TErrorColor[width
+
2
];
for
(
long
x
=
0
;x
<
width
+
2
;
++
x){
_HLineErr[x].dR
=
0
;
_HLineErr[x].dG
=
0
;
_HLineErr[x].dB
=
0
;
}
TErrorColor
*
HLineErr
=&
_HLineErr[
1
];
for
(
long
y
=
0
;y
<
src.height;
++
y){
CvsPic32To16_ErrorDiffuse_Line_2(pDst,pSrc,width,HLineErr);
(TUInt8
*&
)pDst
+=
dst.byte_width;
(TUInt8
*&
)pSrc
+=
src.byte_width;
}
delete[]_HLineErr;
}
速度测试:
//////////////////////////////////////////////////////////////
//CvsPic32To16_ErrorDiffuse_2 166.8 FPS
//////////////////////////////////////////////////////////////
函数效果:
