数字图像设计报告
![数字图像设计报告](https://img.360docs.net/imgdf/06py52jhfob9f17w8w6j-f1.webp)
![数字图像设计报告](https://img.360docs.net/imgdf/06py52jhfob9f17w8w6j-f2.webp)
数字图像处理设计
一、设计目的
1.掌握图像空域平滑、增强方法;
2.掌握图像点运算增强的方法;
3.掌握使用vc++编写图像程序的基本方法。
二、设计原理
1.DIBAPI类:
根据对DIB操作的分析,DIBAPI类的基本操作功能应包括:
(1)DIB文件的读写操作;
(2)提供位图宽度、高度、颜色数目等位图相关信息;
2、图像的打开、关闭、保存
BMP文件里的图像数据是未压缩的,因为图像的数字化处理主要是对图像中的各个像素进行相应的处理,而未压缩的BMP图像中的像素数值正好与实际要处
(一)
图2.1.1 图像读取流程图
图2.1.2 图像显示流程图
BMP位图包括位图文件头结构BITMAPFILEHEADER、位图信息头结构BITMAPINFOHEADER、位图颜色表RGBQUAD和位图像素数据四部分。处理位图时要根据文件的这些结构得到位图文件大小、位图的宽、高、实现调色板、得到位图像素值等等。这里要注意的一点是在BMP位图中,位图的每行像素值要填充到一个四字节边界,即位图每行所占的存储长度为四字节的倍数,不足时将多余位用0填充。
3、图像的锐化处理
图像平滑往往使图像中的边界、轮廓变得模糊,为了减少这类不利效果的影响,这就需要利用图像锐化技术,使图像的边缘变得清晰。图像锐化处理的目的是为了使图像的边缘、轮廓线以及图像的细节变得清晰,经过平滑的图像变得模糊的根本原因是因为图像受到了平均或积分运算,因此可以对其进行逆运算就可以使图像变得清晰。从频率域来考虑,图像模糊的实质是因为其高频分量被衰减,因
此可以用高通滤波器来使图像清晰。
(1)梯度锐化
在图像处理中,一阶微分是通过梯度法来实现的。对于一幅图像用函数f(x,f)表示,定义f(x,f)在点(x,f)处的梯度是一个矢量,定义为:
梯度的方向在函数f(x,f)最大变化率的方向上,梯度的幅度G[f(x,f)] 可由下式算出:
由上式可知,梯度的数值就是f(x,f)在其最大变化率方向上的单位距离所增加的量。对于数字图像而言,微分和可用差分来近似。式(5-6)按差分运算近似后的梯度表达式为:
为便于编程和提高运算速度,在计算精度允许的情况下,可采用绝对差算法近似为:
这种梯度法又称为水平垂直差分法,另一种梯度法是交叉地进行差分计算,称为罗伯特梯度法(Robert Gradient),表示为:
同样,可以采用绝对差算法近似为:
(2)拉普拉斯锐化
拉普拉斯算子是最简单的各向同性微分算子,具有旋转不变性。一个二维图像函数的拉普拉斯变换是各向同性的二阶导数,定义为:
为了更适合于数字图像处理,将该方程表示为离散形式:
从模板形式容易看出,如果在图像中一个较暗的区域中出现了一个亮点,那么用拉普拉斯运算就会使这个亮点变得更亮。因为图像中的边缘就是那些灰度发生跳变的区域,所以拉普拉斯锐化模板在边缘检测中很有用。一般增强技术对于陡峭的边缘和缓慢变化的边缘很难确定其边缘线的位置。但此算子却可用二次微分正峰和负峰之间的过零点来确定,对孤立点或端点更为敏感,因此特别适用于以突出图像中的孤立点、孤立线或线端点为目的的场合。同梯度算子一样,拉普拉斯算子也会增强图像中的噪声,有时用拉普拉斯算子进行边缘检测时,可将图
像先进行平滑处理。
4、图像平滑处理
(1)邻域平均法
最简单的平滑滤波是将原图中一个像素的灰度值和它周围邻近8个像素的灰度值相加,然后将求得的平均值(除以9)作为新图中该像素的灰度值。在实际应用中,也可以根据不同的需要选择使用不同的模板尺寸,如3×3、5×5、7×7、9×9等。邻域平均处理方法是以图像模糊为代价来减小噪声的,且模板尺寸越大,噪声减小的效果越显著。如果是噪声点,其邻近像素灰度与之相差很大,采用邻域平均法就是用邻近像素的平均值来代替它,这样能明显消弱噪声点,使邻域中灰度接近均匀,起到平滑灰度的作用。因此,邻域平均法具有良好的噪声平滑效果,是最简单的一种平滑方法。
(2)中值滤波法
(a)标准一维中值滤波器的定义为:y=med(x1,x2,x3,…..,xn)式中,med 表示取中值操作。中值滤波的滤波方法是对滑动滤波窗口内的像素做大小排序,滤波结果的输出像素值规定为该序列的中值。例如取3×3滑动窗口,中值为窗口内第5个最大的像素值。二维中值滤波的窗口形状和尺寸设计对滤波的效果影响较大,不同的图像内容和不同的应用要求,往往采用不同的形状和尺寸。常用的二维中值滤波窗口有线状、方形、圆形、十字形及圆环形等,窗口尺寸一般选为3,也可以根据滤波效果逐渐增大尺寸,直到获得满意的滤波效果。常用的滤波器为N×N中值滤波器、十字形中值滤波器和N×N最大值滤波器,其他类型的滤波器也可以根据此方法来类推。
三、设计实现方法
1、位图封装打开保存代码:
//文件装载
void CDib::LoadFile(const char* dibFileName)
{
strcpy(m_fileName,dibFileName);
CFile dibFile(m_fileName,CFile::modeRead);
dibFile.Read((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));
if(bitmapFileHeader.bfType == 0x4d42)
{
DWORD fileLength = dibFile.GetLength();
size = fileLength - sizeof(BITMAPFILEHEADER);
//pDib 位图信息头首地址
pDib = (BYTE*)GlobalAllocPtr(GMEM_MOVEABLE,size);
dibFile.Read((void*)pDib,size);
dibFile.Close();
m_pBitmapInfo = (BITMAPINFO*)pDib;//
m_pBitmapInfoHeader = (BITMAPINFOHEADER*)pDib;//
m_pRGB = (RGBQUAD*)(pDib + m_pBitmapInfoHeader->biSize);//
int m_numberOfColors = GetNumberOfColors();
if(m_pBitmapInfoHeader->biClrUsed == 0)
m_pBitmapInfoHeader->biClrUsed = m_numberOfColors;// DWORD colorTableSize = m_numberOfColors * sizeof(RGBQUAD);
//寻找数据区首地址灰度图或24位图
if(m_pBitmapInfoHeader->biBitCount==24)
{
m_pData = pDib + m_pBitmapInfoHeader->biSize;
}
else
{
m_pData = pDib + m_pBitmapInfoHeader->biSize + colorTableSize;
}
//
if(m_pRGB == (RGBQUAD*)m_pData)//没有颜色表
m_pRGB = NULL;//
m_pBitmapInfoHeader->biSizeImage = GetSize();
m_valid = TRUE;//
}
else
{
m_valid = FALSE;
AfxMessageBox("文件不是位图,请打开位图文件!");
}
}
BOOL CDib::IsValid()
{
return m_valid;
}
//获取文件名
char* CDib::GetFileName()
{
return m_fileName;
}
//获取图像宽度
UINT CDib::GetWidth()
{
return(UINT)m_pBitmapInfoHeader->biWidth;
}
//获取图像高度
UINT CDib::GetHeight()
{
return(UINT)m_pBitmapInfoHeader->biHeight;
}
//获取图像大小
DWORD CDib::GetSize()
{
if(m_pBitmapInfoHeader->biSizeImage != 0)
return m_pBitmapInfoHeader->biSizeImage;
else
{
DWORD height = (DWORD)GetHeight();
DWORD width = (DWORD)GetWidth();
return height * width;
}
}
UINT CDib::GetNumberOfColors()
{
int numberOfColors;
//8位图以下计算颜色数numberOfColors
if((m_pBitmapInfoHeader->biClrUsed == 0) &&
m_pBitmapInfoHeader->biBitCount < 9)
{
switch(m_pBitmapInfoHeader->biBitCount)
{
case 1:numberOfColors = 2;break;
case 4:numberOfColors = 16;break;
case 8:numberOfColors = 256;
}
}
else
numberOfColors = (int)m_pBitmapInfoHeader->biClrUsed;
return numberOfColors;
}
//获取数据区
BYTE* CDib::GetData()
{
return m_pData;
}
RGBQUAD* CDib::GetRGB()
{
return m_pRGB;
}
BITMAPINFO* CDib::GetInfo()
{
return m_pBitmapInfo;
}
WORD CDib::PaletteSize(LPBYTE lpDIB)
{
return(DIBNumberColors(lpDIB) * sizeof(RGBTRIPLE));
}
WORD CDib::DIBNumberColors(LPBYTE lpDIB)
{
WORD wBitCount;//位图位数
wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
switch(wBitCount)
{
case 1:
return 2;
case 2:
return 16;
case 8:
return 256;
default:
return 0;
}
}
void CDib::SaveFile(const CString filename)
{
//此函数只能保存处理后宽度、高度均没有改变大小的图像
strcpy(m_fileName,filename);
CFile dibFile(m_fileName,CFile::modeCreate|CFile::modeWrite);
dibFile.Write((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));
dibFile.Write((void*)pDib,size);
dibFile.Close();
}
程序打开原图像运行结果:
2、图像平滑处理领域平均代码如下:
//彩色图像平滑处理领域平均
void CDib::LingYuPingJun()
{
int x = GetWidth();
int y = GetHeight();
int i,j,i0,j0;
long lLineBytes = WIDTHBYTES(x * 24);
unsigned char* lpNew = new unsigned char[y * lLineBytes];
memcpy(lpNew, m_pData, y * lLineBytes);
int sumB,sumG,sumR;
//3 * 3 领域像素点
for(i = 0; i < y - 2; i = i + 3)
{
//x 为像素点的宽度,j表示的是字节的宽度,对于彩色图像一行有x * 3 个有效字节
for(j = 0; j < x * 3 - 8; j = j + 9)
{
// 对像素点B颜色分量求均值
sumB = 0;
sumG = 0;
sumR = 0;
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j; j0 < j + 9; j0 = j0 + 3)
{
//unsigned char* lpSrc = m_pData + lLineBytes * (y - 1 - i0) + j0;
unsigned char* lpSrc = lpNew + lLineBytes * (y - 1 - i0) + j0;
sumB = sumB + *lpSrc;
}
}
sumB = (int)sumB / 9;
// 对像素点B颜色分量重新赋值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j; j0 < j + 9; j0 = j0 + 3)
{
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = sumB;
}
}
// 对像素点B颜色分量求均值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 1; j0 < j + 9; j0 = j0 + 3)
{
//unsigned char* lpSrc = m_pData + lLineBytes * (y - 1 - i0) + j0;
unsigned char* lpSrc = lpNew + lLineBytes * (y - 1 - i0) + j0;
sumG = sumG + *lpSrc;
}
}
sumG = (int)sumG / 9;
// 对像素点G颜色分量重新赋值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 1; j0 < j + 9; j0 = j0 + 3)
{
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = sumG;
}
}
// 对像素点B颜色分量求均值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 2; j0 < j + 9; j0 = j0 + 3)
{
//unsigned char* lpSrc = m_pData + lLineBytes * (y - 1 - i0) + j0;
unsigned char* lpSrc = lpNew + lLineBytes * (y - 1 - i0) + j0;
sumR = sumR + *lpSrc;
}
}
sumR = (int)sumR / 9;
// 对像素点R颜色分量重新赋值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 2; j0 < j + 9; j0 = j0 + 3)
{
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = sumR;
}
}
}
}
}
运行结果图:
3、中值滤波代码:
//彩色图像平滑处理中值平滑滤波
void CDib::ZhongZhiLvBo()
{
int x = GetWidth();
int y = GetHeight();
int i,j,i0,j0,k0;
long lLineBytes = WIDTHBYTES(x * 24);
unsigned char* lpNew = new unsigned char[y * lLineBytes];
memcpy(lpNew, m_pData, y * lLineBytes);
int temp[9];
int tempdata;
//3 * 3 领域像素点
for(i = 0; i < y - 2; i = i + 3)
{
//x 为像素点的宽度,j表示的是字节的宽度,对于彩色图像一行有x * 3 个有效字节
for(j = 0; j < x * 3 - 8; j = j + 9)
{
// 对像素点B颜色分量求均值
k0=0;
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j; j0 < j + 9; j0 = j0 + 3)
{
//unsigned char* lpSrc = m_pData + lLineBytes * (y - 1 - i0) + j0;
temp[k0]= *(lpNew + lLineBytes * (y - 1 - i0) + j0);
k0++;
}
}
//求中值
for(i0 = 0; i0 < 8; i0++)
{
for(j0 =i0; j0 <9 ; j0++)
{
if(temp[i0]>temp[j0])
{
tempdata=temp[i0];
temp[i0]=temp[j0];
temp[j0]=tempdata;
}
}
}
// 对像素点B颜色分量重新赋值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j; j0 < j + 9; j0 = j0 + 3)
{
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = temp[4];
}
}
// 对像素点G颜色分量求均值
k0=0;
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 1; j0 < j + 9; j0 = j0 + 3)
{
temp[k0]= *(lpNew + lLineBytes * (y - 1 - i0) + j0);
k0++;
}
}
//求中值
for(i0 = 0; i0 < 8; i0++)
{
for(j0 =i0; j0 <9 ; j0++)
{
if(temp[i0]>temp[j0])
{
tempdata=temp[i0];
temp[i0]=temp[j0];
temp[j0]=tempdata;
}
}
}
// 对像素点G颜色分量重新赋值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 1; j0 < j + 9; j0 = j0 + 3)
{
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = temp[4];
}
}
// 对像素点R颜色分量求均值
k0=0;
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 2; j0 < j + 9; j0 = j0 + 3)
{
temp[k0]= *(lpNew + lLineBytes * (y - 1 - i0) + j0);
k0++;
}
}
//求中值
for(i0 = 0; i0 < 8; i0++)
{
for(j0 =i0; j0 <9 ; j0++)
{
if(temp[i0]>temp[j0])
{
tempdata=temp[i0];
temp[i0]=temp[j0];
temp[j0]=tempdata;
}
}
}
// 对像素点R颜色分量重新赋值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 2; j0 < j + 9; j0 = j0 + 3)
{
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = temp[4];
}
}
}
}
}
运行结果如下:
4、图像锐化梯度锐化代码:
// 彩色图像梯度锐化
void CDib::TiDuRuiHua()
{
int x = GetWidth();
int y = GetHeight();
int i,j;
long lLineBytes = WIDTHBYTES(x * 24);
unsigned char* lpNew = new unsigned char[y * lLineBytes];
memcpy(lpNew, m_pData, y * lLineBytes);
//3 * 3 领域像素点
for(i = 1; i < y; i++)
{
//x 为像素点的宽度,j表示的是字节的宽度,对于彩色图像一行有x * 3 个有效字节
for(j = 3; j < x * 3 - 2; j = j + 3)
{
unsigned char* lpSrc1 = lpNew + lLineBytes * (y - 1 - i) + j;
unsigned char* lpSrc2 = lpNew + lLineBytes * (y - 1 - i) + j + 1;
unsigned char* lpSrc3 = lpNew + lLineBytes * (y - 1 - i) + j + 2;
//左上角像素点
unsigned char* lpSrc11 = lpNew + lLineBytes * (y - 1 - i + 1) + j - 3;
unsigned char* lpSrc22 = lpNew + lLineBytes * (y - 1 - i + 1) + j + 1 - 3;
unsigned char* lpSrc33 = lpNew + lLineBytes * (y - 1 - i + 1) + j + 2 - 3;
*(m_pData + lLineBytes * (y - 1 - i) + j) += abs(*lpSrc1 - *lpSrc11) / 4;
if(*(m_pData + lLineBytes * (y - 1 - i) + j) > 255)
*(m_pData + lLineBytes * (y - 1 - i) + j) = 255;
*(m_pData + lLineBytes * (y - 1 - i) + j + 1) += abs(*lpSrc2 - *lpSrc22) / 4;
if(*(m_pData + lLineBytes * (y - 1 - i) + j + 1) > 255)
*(m_pData + lLineBytes * (y - 1 - i) + j + 1) = 255;
*(m_pData + lLineBytes * (y - 1 - i) + j + 2) += abs(*lpSrc3 - *lpSrc33) / 4;
if(*(m_pData + lLineBytes * (y - 1 - i) + j + 2) > 255)
*(m_pData + lLineBytes * (y - 1 - i) + j + 2) = 255;
}
}
}
运行结果:
5、拉普拉斯锐化代码:
// 彩色图像中等高通滤波
void CDib::GaoTongLvBo()
{
int x = GetWidth();
int y = GetHeight();
int i,j,i0,j0;
long lLineBytes = WIDTHBYTES(x * 24);
unsigned char* lpNew = new unsigned char[y * lLineBytes];
memcpy(lpNew, m_pData, y * lLineBytes);
int sumB,sumG,sumR;
int moban[9] = {0,-1,0,-1,5,-1,0,-1,0};//小数注意定义时用double
int t1,t2,t3;
//3 * 3 领域像素点
for(i = 0; i < y - 2; i++)
{
//x 为像素点的宽度,j表示的是字节的宽度,对于彩色图像一行有x * 3 个有效字节
for(j = 0; j < x * 3 - 8; j++)
{
// 对像素点B颜色分量求均值
sumB = 0,sumG = 0,sumR = 0;
t1 = 0,t2 = 0,t3 = 0;
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j; j0 < j + 9; j0 = j0 + 3)
{
//unsigned char* lpSrc = m_pData + lLineBytes * (y - 1 - i0) + j0;
unsigned char* lpSrc = lpNew + lLineBytes * (y - 1 - i0) + j0;
}
}
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j; j0 < j + 9; j0 = j0 + 3)
{
if(abs(sumB) > 255)
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = 255;
else
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = abs(sumB);
}
}
// 对像素点B颜色分量求均值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 1; j0 < j + 9; j0 = j0 + 3)
{
//unsigned char* lpSrc = m_pData + lLineBytes * (y - 1 - i0) + j0;
unsigned char* lpSrc = lpNew + lLineBytes * (y - 1 - i0) + j0;
sumG = sumG + (*lpSrc) * moban[t2++];
}
}
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 1; j0 < j + 9; j0 = j0 + 3)
{
if(abs(sumG) > 255)
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = 255;
else
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = abs(sumG);
}
}
// 对像素点B颜色分量求均值
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 2; j0 < j + 9; j0 = j0 + 3)
{
//unsigned char* lpSrc = m_pData + lLineBytes * (y - 1 - i0) + j0;
unsigned char* lpSrc = lpNew + lLineBytes * (y - 1 - i0) + j0;
}
}
for(i0 = i; i0 < i + 3; i0++)
{
for(j0 = j + 2; j0 < j + 9; j0 = j0 + 3)
{
if(abs(sumR) > 255)
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = 255;
else
*(m_pData + lLineBytes * (y - 1 - i0) + j0) = abs(sumR);
}
}
}
}
}
运行结果:
四、设计总结
在这一周的设计过程中,我通过查阅资料学习,对VC有了更深一步的了解,在调试代码过程中也出现了不少问题。但是通过和同学交流以及上网查阅资料使这些问题得以解决。在设计过程中,理论联系实践使我对图像平滑和锐化处理有了更深一步的了解,同时我也意识到自己知识的不足,在以后的学习生活中一定会尽力弥补。
五、参考文献
(1)周长发. 精通Visual C++图像处理编程电子工业出版社,2006.6
(2)赵荣椿. 数字图象处理导论西北工业大学出版社, 1996年
(3) 容观澳. 计算机图象处理清华大学出版社, 2000年
(4) 阮秋椅. 数字图像处理学电子工业出版社, 2001年
(5) 章减晋. 图像工程( 上册)一图像处理和分析清华大学出版社,1999年