数字图像处理总结(三)
Part3 灰度变换和空间滤波Intensity transformation and spatial filtering
空间滤波
这部分没啥说的。就是图像卷积,对应元素相乘相加。
图像增强
gamma变换
当gamma值小于1时,图像的整体亮度值得到提升,同时低灰度处的对比度得到增加,更利于分辩低灰度值时的图像细节。
加速方法,先做一个查找表 tab[n] = (byte)(Pow(n/255, r)*255), 然后用查找表对f的每个元素直接查表赋值
byte[,] GammaV2(byte[,]f, double r)
{
byte[] tab = new byte[256];
for(int i=0;i<256;i++)
{
tab[i] = (byte)(Pow(i/255.0, r)*255);
}
return GT(f, tab);
}
byte[,] GT(byte[,]f, byte[]tab)
{
int w = f.GetLength(0);
int h = f.GetLength(1);
byte [,] g = new byte[w,h];
for(int y=0;y<h;y++)
for(int x=0;x<w;x++)
{
g[x,y] = tab[f[x,y]];
}
return g;
}
取反操作image negative
取log
分段线性增强(piece-wise transformation)
- 对比度拉伸
g[x,y] = S(K*(f[x,y]-128)+128);
- 强度级切片
- bit级别切片
亮度增强(brightness transformation)
两种方式:加和乘
直方图处理 histogram processing
基本概念
求解:
for (int y=0;y<h;y++)
for(int x=0;x<w;x++)
his[f[x,y]]+=1;
for(int n=0;n<256;n++)
his[n] = his[n]/(w*h);
显示:
byte[,] f = new byte[256,101];
for (int x=0;x<256;x++)
{
float ymax = 100 - his[x]*100*20; //主要是概率太低了,即便划归到0-100,看不出区别,因此×20, 黑色部分表示具体的概率,因此用100减一下
if (ymax<0) ymax=0;
for (int y=0;y<=ymax;y++)
f[x,y] = 255;
直方图均衡histogram equalization
直方图均衡化是一种简单有效的图像增强技术,通过改变图像的直方图来改变图像中各像素的灰度,主要用于增强动态范围偏小的图像的对比度。原始图像由于其灰度分布可能集中在较窄的区间,造成图像不够清晰。例如,过曝光图像的灰度级集中在高亮度范围内,而曝光不足将使图像灰度级集中在低亮度范围内。采用直方图均衡化,可以把原始图像的直方图变换为均匀分布(均衡)的形式,这样就增加了像素之间灰度值差别的动态范围,从而达到增强图像整体对比度的效果。换言之,直方图均衡化的基本原理是:对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行归并,从而增大对比度,使图像清晰,达到增强的目的。 举个例子,如图1所示,左图为原始图像,右图为直方图均衡化后的图像。
算法:先求前n项和(积分), 然后乘l-1(255)
float[] his = get_histo(f);
float[] sh = new float[256];
/*
for (int n=0;n<256;n++)
for (int i=0;i<n;i++)
sh[n] += his[i];
*/
sh[0] = his[0];
for (int n=1;n<256;n++)
sh[n] = sh[n-1]+his[n];
byte[] tab = new byte[256];
for (int n=1;n<256;n++)
tab[n] = (byte)(sh[n]*255);
return GT(f,tab);
滤波处理 Spatial filtering
基本原理
使用一个滤波模板来进行卷积
float[,] mask = new float[3,3];
mask[0,0] = 0; mask[1,0] = -1; mask[2,0] = 0;
mask[0,1] =-1; mask[1,1] = 5; mask[2,1] = -1;
mask[0,2] = 0; mask[1,2] = -1; mask[2,2] = 0;
byte[,] filter2D(byte[,]f, float[,] mask)
{
int w = f.GetLength(0);
int h = f.GetLength(1);
byte[,] g = new byte[w,h];
int M = mask.GetLength(0)/2;
int N = mask.GetLength(1)/2;
for (int y=N;y<h-N;y++)
for(int x=M;x<w-M;x++)
{
float r = 0;
for(int n=-N;n<=N;n++)
for(int m=-M;m<=M;m++)
r+= f[x+m, y+n] * mask[m+M, n+N];
g[x,y] = S(r);
}
return g;
}
平滑smooth(均值滤波average filter)
float[,] blurMask(int hsize,int vsize)
{
float[,] mask = new float[hsize,vsize];
float v = 1.0f/(hsize*vsize);
for (int m=0;m<hsize;m++)
for (int n=0;n<vsize;n++)
mask[m,n] = v;
return mask;
}
高斯滤波(Gaussian blur)
先离散化再归一化
float[,] gblurMask(double r)
{
int M = (int)(r*3);
if (M==0) M=1;
int N = M;
float[,] mask = new float[2*M+1,2*N+1];
// sampling
for (int m=-M;m<=M;m++)
for (int n=-N;n<=N;n++)
mask[M+m,N+n] = (float)Exp(-(m*m+n*n)/(2*r*r));
// normalized
float s = 0;
for (int m=-M;m<=M;m++)
for (int n=-N;n<=N;n++)
s+=mask[M+m,N+n];
for (int m=-M;m<=M;m++)
for (int n=-N;n<=N;n++)
mask[M+m,N+n] = mask[M+m,N+n]/s;
return mask;
}
中值滤波(median operation)应对椒盐噪声(salt pepper)
取四邻域和自己来进行选择排序
void add_noise(byte[,]f,int s_count,int p_count) // 加噪声
{
int w = f.GetLength(0);
int h = f.GetLength(1);
for (int n=0;n<s_count;n++)
{
int x = (int)(Rand()*(w-1));
int y = (int)(Rand()*(h-1));
f[x,y] = 255;
}
for (int n=0;n<p_count;n++)
{
int x = (int)(Rand()*(w-1));
int y = (int)(Rand()*(h-1));
f[x,y] = 0;
}
}
void order(byte[] a) // sort
{
int len = a.Length;
for (int i=0;i<len-1;i++)
for (int j=i+1;j<len;j++)
{
if (a[i]>a[j])
{
byte t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
byte median(byte[] a) //get median number
{
order(a);
return a[a.Length/2];
}
byte[,] median_filter(byte[,]f) // filter at N4
{
int w = f.GetLength(0);
int h = f.GetLength(1);
byte[,] g = new byte[w,h];
byte[] a = new byte[5];
for(int y=1;y<h-1;y++)
for (int x=1;x<w-1;x++)
{
a[0] = f[x,y];
a[1] = f[x-1,y];
a[2] = f[x+1,y];
a[3] = f[x,y-1];
a[4] = f[x,y+1];
g[x,y] = median(a);
}
return g;
}
梯度和Laplace
表达式如下:
锐化滤波器(sharp filter)
添加了低通分量
float[,] sharp(float k)
{
float[,] mask = new float[3,3];
mask[0,0] = 0; mask[1,0] = -k; mask[2,0] = 0;
mask[0,1] =-k; mask[1,1] =1+4*k; mask[2,1] =-k;
mask[0,2] = 0; mask[1,2] = -k; mask[2,2] = 0;
return mask;
}
高通滤波(high pass filter)
无低通分量
4N:
float[,] lap4P()
{
float[,] mask = new float[3,3];
mask[0,0] =0; mask[1,0] = -1; mask[2,0] =0;
mask[0,1] =-1; mask[1,1] = 4; mask[2,1] =-1;
mask[0,2] =0; mask[1,2] = -1; mask[2,2] =0;
return mask;
}
8N:
float[,] lap8P()
{
float[,] mask = new float[3,3];
mask[0,0] =-1; mask[1,0] = -1; mask[2,0] =-1;
mask[0,1] =-1; mask[1,1] = 8; mask[2,1] =-1;
mask[0,2] =-1; mask[1,2] = -1; mask[2,2] =-1;
return mask;
}
反锐化滤波(Unsharp Masking)
基本步骤:
- 原图-模糊图,得到Gmask
- 原图加上k倍的Gmask
//g[x,y] = (k+1)f[x,y] - kGblur*f[x,y] -kGblur相当于卷积核,中间位置加一个k+1
float[,] unsharpmask(float k,double r)
{
float[,] gmask = gblurMask(r);
int M = gmask.GetLength(0)/2;
int N = gmask.GetLength(1)/2;
float[,] mask = new float[2*M+1,2*N+1];
mask[M,N] = 1+k; //对应原图f[x,y]
for (int m=-M;m<=M;m++)
for (int n=-N;n<=N;n++)
mask[m+M,n+N] = mask[m+M,n+N]-k*gmask[m+M,n+N];
return mask;
}
梯度幅度和幅角(magnitude angle)
sobel算子
float[,] sobelX()
{
float[,] mask = new float[3,3];
mask[0,0] =-1; mask[1,0] = 0; mask[2,0] = 1;
mask[0,1] =-2; mask[1,1] = 0; mask[2,1] = 2;
mask[0,2] =-1; mask[1,2] = 0; mask[2,2] = 1;
return mask;
}
float[,] sobelY()
{
float[,] mask = new float[3,3];
mask[0,0] =-1; mask[1,0] = -2; mask[2,0] =-1;
mask[0,1] = 0; mask[1,1] = 0; mask[2,1] = 0;
mask[0,2] = 1; mask[1,2] = 2; mask[2,2] = 1;
return mask;
}