数字图像处理领域的二十四个典型算法及 vc 实现、第一章
一、256 色转灰度图
二、Walsh 变换
三、二值化变换
四、阈值变换
五、傅立叶变换
六、离散余弦变换
数字图像处理领域的二十四个典型算法及 vc 实现、第二章
七、高斯平滑
八、图像平移
九、图像缩放
十、图像旋转
数字图像处理领域的二十四个典型算法及 vc 实现、第三章
图像处理,是对图像进行分析、加工、和处理,使其满足视觉、心理以及其他要求的
技术。图像处理是信号处理在图像域上的一个应用。目前大多数的图像是以数字形式存储,
因而图像处理很多情况下指数字图像处理。
本文接下来,简单粗略介绍下数字图像处理领域中的 24 个经典算法,然后全部算法用
vc 实现。由于篇幅所限,只给出某一算法的主体代码。
ok,请细看。
一、256 色转灰度图
算法介绍(百度百科):
什么叫灰度图?任何颜色都有红、绿、蓝三原色组成,假如原来某点的颜色为 RGB(R,
G,B),那么,我们可以通过下面几种方法,将其转换为灰度:
1.浮点算法:Gray=R*0.3+G*0.59+B*0.11
2.整数方法:Gray=(R*30+G*59+B*11)/100
3.移位方法:Gray =(R*28+G*151+B*77)>>8;
4.平均值法:Gray=(R+G+B)/3;
5.仅取绿色:Gray=G;
通过上述任一种方法求得 Gray 后,将原来的 RGB(R,G,B)中的 R,G,B 统一用 Gray 替
换,形成新的颜色 RGB(Gray,Gray,Gray),用它替换原来的 RGB(R,G,B)就是灰度图了。
灰度分为 256 阶。所以,用灰度表示的图像称作灰度图。
程序实现:
ok,知道了什么叫灰度图,下面,咱们就来实现此 256 色灰度图。
这个 Convert256toGray(),即是将 256 色位图转化为灰度图:
void Convert256toGray(HDIB hDIB)
{
LPSTR lpDIB;
// 由 DIB 句柄得到 DIB 指针并锁定 DIB
lpDIB = (LPSTR) ::GlobalLock((HGLOBAL)hDIB);
// 指向 DIB 象素数据区的指针
LPSTR lpDIBBits;
// 指向 DIB 象素的指针
BYTE * lpSrc;
// 图像宽度
LONG lWidth;
// 图像高度
LONG lHeight;
// 图像每行的字节数
LONG lLineBytes;
// 指向 BITMAPINFO 结构的指针(Win3.0)
LPBITMAPINFO lpbmi;
// 指向 BITMAPCOREINFO 结构的指针
LPBITMAPCOREINFO lpbmc;
// 获取指向 BITMAPINFO 结构的指针(Win3.0)
lpbmi = (LPBITMAPINFO)lpDIB;
// 获取指向 BITMAPCOREINFO 结构的指针
lpbmc = (LPBITMAPCOREINFO)lpDIB;
// 灰度映射表
BYTE bMap[256];
// 计算灰度映射表(保存各个颜色的灰度值),并更新 DIB 调色板
int i,j;
for (i = 0; i < 256; i ++)
{
// 计算该颜色对应的灰度值
bMap[i] = (BYTE)(0.299 * lpbmi->bmiColors[i].rgbRed +
0.587 * lpbmi->bmiColors[i].rgbGreen +
0.114 * lpbmi->bmiColors[i].rgbBlue + 0.5);
// 更新 DIB 调色板红色分量
lpbmi->bmiColors[i].rgbRed = i;
// 更新 DIB 调色板绿色分量
lpbmi->bmiColors[i].rgbGreen = i;
// 更新 DIB 调色板蓝色分量
lpbmi->bmiColors[i].rgbBlue = i;
// 更新 DIB 调色板保留位
lpbmi->bmiColors[i].rgbReserved = 0;
}
// 找到 DIB 图像象素起始位置
lpDIBBits = ::FindDIBBits(lpDIB);
// 获取图像宽度
lWidth = ::DIBWidth(lpDIB);
// 获取图像高度
lHeight = ::DIBHeight(lpDIB);
// 计算图像每行的字节数
lLineBytes = WIDTHBYTES(lWidth * 8);
// 更换每个象素的颜色索引(即按照灰度映射表换成灰度值)
//逐行扫描
for(i = 0; i < lHeight; i++)
{
//逐列扫描
for(j = 0; j < lWidth; j++)
{
// 指向 DIB 第 i 行,第 j 个象素的指针
lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
// 变换
*lpSrc = bMap[*lpSrc];
}
}
//解除锁定
::GlobalUnlock ((HGLOBAL)hDIB);
}
变换效果(以下若无特别说明,图示的右边部分都是为某一算法变换之后的效果):
二、Walsh 变换
算法介绍:
有关 Walsh 变换的深入介绍,请看此论文:
http://www.informatics.org.cn/doc/ucit200510/ucit20051005.pdf
程序实现:
-2 的幂数
- 指向时域值的指针
- 指向频域值的指针
函数名称:WALSH()
参数:
double * f
double * F
r
返回值:无。
说明:该函数用来实现快速沃尔什-哈达玛变换。
VOID WINAPI WALSH(double *f, double *F, int r)
{
// 沃尔什-哈达玛变换点数
LONG count;
// 循环变量
int i,j,k;
// 中间变量
int bfsize,p;
double *X1,*X2,*X;
// 计算快速沃尔什变换点数
count = 1 << r;
// 分配运算所需的数组
X1 = new double[count];
X2 = new double[count];
// 将时域点写入数组 X1
memcpy(X1, f, sizeof(double) * count);
// 蝶形运算
for(k = 0; k < r; k++)
{
for(j = 0; j < 1<
X1 = X2;
X2 = X;
}
// 调整系数
for(j = 0; j < count; j++)
{
p = 0;
for(i = 0; i < r; i++)
{
if (j & (1<
int wp;
int hp;
// 图像每行的字节数
LONG lLineBytes;
// 计算图像每行的字节数
lLineBytes = WIDTHBYTES(lWidth * 8);
// 赋初值
w = 1;
h = 1;
wp = 0;
hp = 0;
// 计算进行离散余弦变换的宽度和高度(2 的整数次方)
while(w * 2 <= lWidth)
{
w *= 2;
wp++;
}
while(h * 2 <= lHeight)
{
h *= 2;
hp++;
}
// 分配内存
double *f = new double[w * h];
double *F = new double[w * h];
// 列
for(i = 0; i < w; i++)
{
// 行
for(j = 0; j < h; j++)
{
// 指向 DIB 第 j 行,第 i 个象素的指针
lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - j) + i;
// 给时域赋值
f[j + i * w] = *(lpSrc);
}
}
// 调用快速沃尔什-哈达玛变换
WALSH(f, F, wp + hp);
// 列
for(i = 0; i < w; i++)
{
// 行
for(j = 0; j < h; j++)
{
// 计算频谱
dTemp = fabs(F[i * w + j] * 1000);
// 判断是否超过 255
if (dTemp > 255)
{
// 对于超过的,直接设置为 255
dTemp = 255;
}
// 指向 DIB 第 j 行,第 i 个象素的指针
lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - j) + i;
// 更新源图像
* (lpSrc) = (BYTE)(dTemp);
}
}
//释放内存
delete f;
delete F;
// 返回
return TRUE;
}
变换效果:
三、二值化变换
算法描述:
二值化是图像分割的一种方法。在二值化图象的时候把大于某个临界灰度值的像素灰度
设为灰度極大值,把小于这个值的像素灰度设为灰度極小值,从而实现二值化。
根据阈值选取的不同,二值化的算法分为固定阈值和自适应阈值。 比较常用的二值化方
法则有:双峰法、P 参数法、迭代法和 OTSU 法等。
程序实现:
void CMyDIPView::OnDraw(CDC* pDC)
{
CMyDIPDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(pDoc->m_hDIB == NULL)
return ;
// TODO: add draw code for native data here
int i,j;
unsigned char *lpSrc;
// Size of DIB - x
// Size of DIB - y
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->m_hDIB);
int cxDIB = (int) ::DIBWidth(lpDIB);
int cyDIB = (int) ::DIBHeight(lpDIB);
LPSTR lpDIBBits=::FindDIBBits (lpDIB);
// 计算图像每行的字节数
long lLineBytes = WIDTHBYTES(cxDIB * 8);
// 每行
for(i = 0; i < cyDIB; i++)
{
// 每列
for(j = 0; j < cxDIB; j++)