图像增强Image Enhancement
图像增强基本概念
图像增强(Image Enhancement)是指对图像的亮度、对比度、颜色等进行调节,改善视觉 效果,以便于人眼观察的相关技术与方法的统称。
图像增强中,从位于$(x,y)$处的像素点$g(x,y)$到增强后像素点$G(x,y)$到包括两种方式:
- 点运算: $G(x,y) = f(g(x,y))$
- 领域运算:$G(x,y) = g(x,y) * 8-[\sum_{i=-1}^1\sum_{j=-1}^1g(x+j, y+i)-g(x,y)]$
对于领域运算需要进行饱和处理(上溢255,下溢0):
$G(x,y)=max(0,min(g(x,y),255))$
线性拉伸
对某个像素点进行线性变换,属于点运算方式:$G(x,y)=k*g(x,y)+b$。
其图像灰度的方差与$k\lessgtr1$相关,亮暗程度与$(k\stackrel{?}{=}1,b\lessgtr0)$相关。
void LinearStretchDemo(BYTE *pGryImg, int width, int height, double k, double b, BYTE *pResImg) {
BYTE *pCur, *pEnd, *pRes;
pEnd = pGryImg+width*height;
for (pCur = pGryImg, pRes = pResImg; pCur<pEnd; pCur++) {
*(pRes++) = max(0, min(255, (int)(k*(*pCur)+b))); //要对k*(*pCur)+b执行饱和运算;
}
return;
}
此算法对于每一个像素,都需要进行较多运算,为了减少运算,可以采用查找表LUT进行优化,即先计算0~255灰度在线性变换后的结果,保存到查找表LUT中,再将每个像素在查找表进行索引。
void RmwLinearStretch(BYTE *pGryImg, int width, int height, double k, double b, BYTE *pResImg) {
BYTE *pCur, *pEnd, *pRes;
//int LUT[256]; //因为只有[0,255]256个灰度值
BYTE LUT[256]; //因为只有[0,255]256个灰度值
// step.1-------------生成查找表------------------------//
for (int g = 0; g<256; g++) {
LUT[g] = max(0, min(255, (int)(k*g+b))); //勿忘饱和运算
}
// step.2-------------进行变换--------------------------//
pEnd = pGryImg+width*height;
for (pCur = pGryImg, pRes = pResImg; pCur<pEnd; pCur++) {
*(pRes++) = LUT[*pCur];
}
return;
}
均值方差规定化
需要说明的是,图像中可以定义亮度(Bright)和对比度(Contrast)分别为:
$ bright=\frac{\sum_{y=0}^{height-1}\sum_{x=0}^{width-1}g(x,y)}{width*height} $
$ contract=\sqrt{\frac{\sum_{y=0}^{height-1}\sum_{x=0}^{width-1}(g(x,y)-bright)^2}{width*height-1}} $
而均值方差的意义在于通过调整图像的亮度和对比度到固定值实现图像增强。
亮度和对比度分别为$(b_1,c_1)\longrightarrow(b_2,c_2)$,可以推出运算函数:$G=\frac{c_2}{c_1}(g-b_1)+b_2$。
直方图优化 (Histogram)
直方图(histogram)是反映一幅图像中像素灰度值分布的统计表。
// 统计直方图
void RmwGetHistogram(BYTE *pGryImg, int width, int height, int *histogram) {
BYTE *pCur, *pEnd = pGryImg+width*height;
// step.1-------------初始化----------------------------//
//for (int g = 0; g<256; g++) histogram[g] = 0;
memset(histogram, 0, sizeof(int)*256);
// step.2-------------直方图统计------------------------//
for (pCur = pGryImg; pCur<pEnd; ) histogram[*(pCur++)]++;
return;
}
// 求直方图中灰度最大和最小的值
void GetMinMaxGry(int *histogram, int *minGry, int *maxGry) {
int g;
// step.1-------------求最小值--------------------------//
for (g = 0; g<256; g++) {
if (histogram[g]) break;
}
*minGry = g;
// step.2-------------求最大值--------------------------//
for (g = 255; g>=0; g--) {
if (histogram[g]) break;
}
*maxGry = g;
return;
}
// 根据直方图求亮度和对比度
void GetBrightContrast(int *histogram, double *bright, double *contrast) {
int g;
int sum, num;
double fsum;
// step.1-------------求亮度----------------------------//
for (sum = num = 0, g = 0; g<256; g++) {
sum += histogram[g]*g;
num += histogram[g];
}
*bright = sum*1.0/num;
// step.2-------------求对比度--------------------------//
for (fsum = 0.0, g = 0; g<256; g++) {
fsum += histogram[g]*(g-*bright)*(g-*bright);
}
*contrast = sqrt(fsum/(num-1));
return;
}
直方图均衡化
假设转换后的结果图像有N个灰度级,像素总数为S个,等概率分布下每个灰度级拥有$\frac{S}{N}$个像素。
$\sum_{i=1}^gH_1(g)=\sum_{i=1}^GH_2(G)=G*\frac{S}{N}$
进一步可以得到:
$G=\frac{N*\sum_{i=1}^gH_1(g)}{S}$
其中$\sum_{i=1}^{g}H_1(g)$表示从灰度级1到灰度级g的像素个数,记$A(g)=\sum_{i=1}^{g}H_1(g)$,则可以推导出:
$A(1)=H(1)$ $A(2)=H(1)+H(2)$ $A(i)=A(i-1)+H(i)$
// 标准的直方图均衡化
void RmwHistogramEqualizeDemo(BYTE *pGryImg, int width, int height) {
BYTE *pCur, *pEnd = pGryImg+width*height;
int histogram[256], A[256], LUT[256], g;
// step.1-------------求直方图--------------------------//
memset(histogram, 0, sizeof(int)*256);
for (pCur = pGryImg; pCur<pEnd;) histogram[*(pCur++)]++;
// step.2-------------求A[g],N-------------------------//
for (g = 1, A[0] = histogram[0]; g<256; g++) A[g]= A[g-1]+histogram[g];
// step.3-------------求LUT[g]-------------------------//
for (g = 0; g<256; g++) LUT[g] = 255*A[g]/(width*height);
// step.4-------------查表------------------------------//
for (pCur = pGryImg; pCur<pEnd;) *(pCur++) = LUT[*pCur];
return;
}
// 优化后的直方图均衡化
void RmwHistogramEqualize(BYTE *pGryImg, int width, int height) {
BYTE *pCur, *pEnd = pGryImg+width*height;
int histogram[256], LUT[256], A, g;
// step.1-------------求直方图--------------------------//
memset(histogram, 0, sizeof(int)*256);
for (pCur = pGryImg; pCur<pEnd;) histogram[*(pCur++)]++;
// step.2-------------求LUT[g]-------------------------//
A = histogram[0];
LUT[0] = 255*A/(width*height);
for (g = 1; g<256; g++) {
A += histogram[g];
LUT[g] = 255*A/(width*height);
}
// step.3-------------查表------------------------------//
for (pCur = pGryImg; pCur<pEnd;) *(pCur++) = LUT[*pCur];
return;
}