图像增强
图像增强的方法是通过一定手段对原图像附加一些信息或变换数据,有选择地突出图像中感兴趣的特征或者抑制(掩盖)图像中某些不需要的特征,使图像与视觉响应特性相匹配。
图像对比度
图像对比度计算方式如下:
C
=
∑
δ
δ
(
i
,
j
)
P
δ
(
i
,
j
)
C=\displaystyle\sum_{{\delta}}\delta(i,j)P_\delta(i,j)
C=δ∑δ(i,j)Pδ(i,j)
其中,
δ
(
i
,
j
)
=
∣
i
−
j
∣
\delta(i,j)=\lvert i-j\rvert
δ(i,j)=∣i−j∣,即相邻像素间的灰度差;
P
δ
(
i
,
j
)
P_\delta(i,j)
Pδ(i,j)为相邻像素灰度差为
δ
\delta
δ的像素分布概率。可以是四邻域,也可以是八邻域。具体过程如下:
原始图像为:
L
=
[
1
3
5
2
1
3
3
6
0
]
L=\begin{bmatrix} 1 & 3 &5\\ 2 & 1 &3 \\ 3 & 6&0 \end{bmatrix}
L=
123316530
按照四邻域进行计算,对比度
C
L
=
[
(
1
2
+
2
2
)
+
(
2
2
+
2
2
+
2
2
)
+
(
1
2
+
1
2
+
1
2
)
+
(
2
2
+
2
2
+
1
2
+
5
2
)
+
(
2
2
+
2
2
+
3
2
)
+
(
1
2
+
3
2
)
+
(
5
2
+
3
2
+
6
2
)
+
(
3
2
+
6
2
)
/
22
C_L=\lbrack(1^2+2^2)+(2^2+2^2+2^2)+(1^2+1^2+1^2)+(2^2+2^2+1^2+5^2)+(2^2+2^2+3^2)+(1^2+3^2)+(5^2+3^2+6^2)+(3^2+6^2)/22
CL=[(12+22)+(22+22+22)+(12+12+12)+(22+22+12+52)+(22+22+32)+(12+32)+(52+32+62)+(32+62)/22。22就是平方的个数。
1.对比度展宽
对比度展宽的目的是通过增强图像的亮暗对比程度而改善画质,使图像的显示效果更加清晰。
线性对比度展宽
通过抑制非重要信息的对比度来腾出空间给重要信息进行对比度的展宽。
原图的灰度为
f
(
i
,
j
)
f(i,j)
f(i,j),处理后的图像灰度为
g
(
i
,
j
)
g(i,j)
g(i,j)。原图中的重要景物的灰度分布假设分布在
[
f
a
,
f
b
]
\lbrack f_a,f_b\rbrack
[fa,fb]的范围内,则对比度线性展宽的目的是使处理后图像的重要景物的灰度分布在
[
g
a
,
g
b
]
\lbrack g_a,g_b\rbrack
[ga,gb]的范围内,当
Δ
f
=
(
f
b
−
f
a
)
<
Δ
g
=
(
g
b
−
g
a
)
\varDelta f=(f_b-f_a)<\varDelta g=(g_b-g_a)
Δf=(fb−fa)<Δg=(gb−ga),则可达到对比度展宽的目的。
计算方式如下:
g
(
i
,
j
)
=
{
α
f
(
i
,
j
)
0
≤
f
(
i
,
j
)
<
a
β
(
f
(
i
,
j
)
−
a
)
+
g
a
a
≤
f
(
i
,
j
)
<
b
γ
(
f
(
i
,
j
)
−
b
)
+
g
b
b
≤
f
(
i
,
j
)
<
255
g(i,j)= \begin{cases} \alpha f(i,j) &\text{ } 0\le f(i,j)<a \\ \beta (f(i,j)-a)+g_a &\text{ } a\le f(i,j)<b \\ \gamma (f(i,j)-b)+g_b &b\le f(i,j)<255 \end{cases}
g(i,j)=⎩
⎨
⎧αf(i,j)β(f(i,j)−a)+gaγ(f(i,j)−b)+gb 0≤f(i,j)<a a≤f(i,j)<bb≤f(i,j)<255
其中,
α
=
g
a
f
a
,
β
=
g
b
−
g
a
f
b
−
f
a
,
γ
=
255
−
g
b
255
−
f
b
\alpha =\frac{g_a}{f_a},\beta =\frac{g_b-g_a}{f_b-f_a},\gamma =\frac{255-g_b}{255-f_b}
α=faga,β=fb−fagb−ga,γ=255−fb255−gb。
C++代码如下:
cv::Mat image = cv::imread("Lena.bmp");
cv::Mat grayImage(image.size(), CV_8UC1);
cv::Mat dstImage(grayImage.size(), CV_8UC1);
cv::cvtColor(image, grayImage, CV_BGR2GRAY);
int fa = 50, fb = 100;
float ga = 30, gb = 120;
for (int row = 0; row < grayImage.rows; row++)
{
uchar *currentData = grayImage.ptr<uchar>(row);
for (int col = 0; col < grayImage.cols; col++)
{
if (*(currentData + col) >= 0 && *(currentData + col) < fa)
{
dstImage.at<uchar>(row, col) = uchar(ga / fa * (*(currentData + col)));
}
if (*(currentData + col) >= fa && *(currentData + col) < fb)
{
dstImage.at<uchar>(row, col) = uchar((gb-ga) / (fb-fa) * (*(currentData + col)-fa)+ga);
}
if (*(currentData + col) >= fb && *(currentData + col) < 255)
{
dstImage.at<uchar>(row, col) = uchar((255-gb) / (255-fb) * (*(currentData + col)-fb)+gb);
}
}
//currentData++;
}
结果如下:
非线性对比度展宽
通过一个光滑的映射曲线,使得处理后图像的灰度变化比较光滑。计算公式如下:
g
(
i
,
j
)
=
c
⋅
l
g
(
1
+
f
(
i
,
j
)
)
g(i,j)=c\cdot lg(1+f(i,j))
g(i,j)=c⋅lg(1+f(i,j))
实际上完成的作用是,抑制高亮度区域,扩展低亮度区域。
2.直方图均衡化
在信息论中有这样一个结论:当数据的分布接近均匀分布的时候,数据所承载的信息量(熵)为最大。
灰度直方图的基本原理是:对在图像中像素个数多的灰度级(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行归并。
直方图均衡化方法的具体步骤如下:
- 求出原图 f ( i , j ) M × N f(i,j)_{M\times N} f(i,j)M×N的灰度直方图,设用256维的向量 h f h_f hf表示;
- 有
h
f
h_f
hf求原图的灰度分布概率,记作
p
f
p_f
pf,则有
p
f
(
i
)
=
1
N
f
⋅
h
f
(
i
)
,
i
=
0
,
1
,
…
,
255
p_f(i)=\frac{1}{N_f}\cdot h_f(i),i=0,1,\dots ,255
pf(i)=Nf1⋅hf(i),i=0,1,…,255
其中, N f = M × N N_f=M\times N Nf=M×N( M , N M,N M,N分别为图像的长和宽)为图像的总像素个数; - 计算图像各个灰度值的累计分布概率,记作
p
a
p_a
pa,则有
p
a
(
i
)
=
∑
k
=
0
i
p
f
(
k
)
,
i
=
1
,
2
,
…
,
255
p_a(i)=\displaystyle\sum_{k=0}^ip_f(k),i=1,2,\dots ,255
pa(i)=k=0∑ipf(k),i=1,2,…,255
其中,令 p a ( 0 ) = 0 p_a(0)=0 pa(0)=0。 - 进行直方图均衡化计算,得到处理后图像的像素值 g ( i , j ) g(i,j) g(i,j)为: g ( i , j ) = 255 ⋅ p a ( k ) g(i,j)=255\cdot p_a(k) g(i,j)=255⋅pa(k)
C++代码如下所示:
cv::Mat image = cv::imread("Lena.bmp");
cv::Mat src(image.size(), CV_8UC1);
//转为灰度图像
cv::cvtColor(image, src, CV_BGR2GRAY);
cv::Mat dst(image.size(), CV_8UC1);
float hf[256] = { 0 };
for (int row = 0; row < src.rows; row++)
{
uchar *currentData = src.ptr<uchar>(row);
for (int col = 0; col < src.cols; col++)
{
hf[*(currentData + col)] += 1;
}
}
float pf[256] = { 0 };
for (int i = 0; i < 256; i++)
{
pf[i] = hf[i] / (src.rows*src.cols);
}
float pa[256] = { 0 };
for (int i = 1; i < 256; i++)
{
float sumNumber = 0;
for (int j = 0; j < i+1; j++)
{
sumNumber += pf[j];
}
pa[i] = sumNumber;
}
for (int row = 0; row < dst.rows; row++)
{
uchar * currentData = dst.ptr<uchar>(row);
for (int col = 0; col < dst.cols; col++)
{
*(currentData + col) = uchar(255 * pa[src.at<uchar>(row, col)]);
}
}
结果展示: