数字图像处理(Digital Image Processing)
是指用计算机处理图像,主要包括:
(1)点运算:针对图像的像素进行基本数学运算。点运算可以有效的改变图像的直方图分布,可以有效提高图像的分辨率,以及图像均衡的操作。
(2)几何处理:主要包括图像的坐标 变换,图像的移动、缩小、放大、旋转,多个图像的配准以及图像扭曲校正等。图像的扭曲校正功能可以将变形的图像进行几何校正。
(3)图像增强:图像增强的作用主要是突出图像中重要的信息,同时减弱或者去除不重要的信息。常用方法有直方图增强和为彩色增强。
(4)图像复原:图像复原的主要目的是去除干扰和模糊,从而恢复图像的原样,例如去噪声复原处理。
(5)图像形态学处理:图像形态学是数学形态学的延伸,利用图像形态学处理技术,可以实现图像的腐蚀、细化和分割等效果。
(6)图像编码:利用图像信号的统计特性及人类视觉特性对图像进行高效编码,从而达到压缩图像的目的。
(7)图像重建:利用采集到的数据来重建图像,起源于CT技术的发展,是一门新兴的数字图像处理技术。图像重建的主要算法有代数法、迭代法、傅里叶反投影法和使用最广泛的卷积反投影法等。
(8)模式识别:包括三种方法统计识别法、句法结构模式识别法和模糊识别法。
图像和调色板
图像是由三维客观世界映射到二维所得到的结果,因此一幅图像可以用二维的含数f(x,y)来表示,这里的x,y表示二维空间中一个坐标点的位置,f表示图像在点(x,y)出的某种属性,如亮度,常见的图像是连续的,即f、x、y的取值是连续的。为了是计算机能够对图像进行处理,需要对图像进行采样、量化和编码,从而形成一幅离散的数字图像。因此,通常用I=f(x,y)来表示一幅数字图像,也可以用二维矩阵的形式来描述一幅M*N的数字图像。
矩阵中的各个元素称为像素,一幅数字图现象是由在水平方向上的M列像素和垂直方向上的N行像素构成的,在数值上等于数字图像在该坐标点处的灰度值。
所谓调色板就是在16色或者256色显示系统中,是图像中出现最频繁的16种或256种颜色所组成的颜色表。对这些颜色按4位或者8位(即0到15或者255)进行编号,每一个编号代表其中的一种颜色。这种颜色编号叫做颜色的索引号,4位或者8位的索引号与24位的颜色值的对应表叫做颜色查找表。使用调色板的图像叫做调色板图像,他们的像素值并不是颜色值,而是颜色在调色板查找表中的索引号。
Windows使用2种不同的位图,即设备相关位图DDB(Device Dependent Bitmap)和设备无关位图DIB(Device Independent Bitmap)。DIB位图文件中包含该位图的逻辑调色板的颜色表,其像素值是该调色板中的颜色索引值。DDB位图中不包含调色板信息,其像素值是该系统调色板中的颜色索引值。在结构上,DIB与DDB的主要区别在于DIB包含一个名为RGBQUUAD的结构,它描述了DIB位图的颜色表。
图片的读取
1.在vs2010中创建MFC基于对话框的应用程序
2.在资源视图的Dialog界面创建图片显示窗口和控制按钮,方法是在对话框中添加picture control和Button 等控件。分别修改各个控件的ID和Caption。
3.双击打开按钮,MFC自动添加消息响应函数void CBMP_RSYDlg::OnBnClickedButtonOpen()
,并在消息响应函数中添加如下代码:
CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"bmp(*.bmp)|*.bmp||",this);
if (dlg.DoModal()!=IDOK)
{
MessageBox("图片打开失败");
return;
}
m_strSrcBmpPath = dlg.GetPathName();
CFile file;
file.Open(m_strSrcBmpPath,CFile::modeRead);
file.Read(m_pBmpFileHeader,14);
file.Seek(14,CFile::begin);
file.Read(m_pBmpInfo, 40+256*4);
if (m_pBmpInfo->bmiHeader.biBitCount==8)//灰度图像,有调色板
{
file.Seek(14+40+256*4,CFile::begin);
}
else if (m_pBmpInfo->bmiHeader.biBitCount==24)//彩色图像,无调色板
{
file.Seek(14+40,CFile::begin);
}
int iWidth = m_pBmpInfo->bmiHeader.biWidth;
int iHeight = m_pBmpInfo->bmiHeader.biHeight;
int iImgSize = m_pBmpInfo->bmiHeader.biSizeImage;
int iXPels = m_pBmpInfo->bmiHeader.biXPelsPerMeter;
int iYPels = m_pBmpInfo->bmiHeader.biYPelsPerMeter;
int biClrUsed = m_pBmpInfo->bmiHeader.biClrUsed;
int biClrImportant = m_pBmpInfo->bmiHeader.biClrImportant;
file.Read(m_pSrcBuf, m_pBmpInfo->bmiHeader.biSizeImage);
file.Close();
Invalidate();
4.要想将读取的图像显示出来,需要在OnPaint()
函数中载入图像并和picture control关联,具体代码如下:
CDC *m_pDC = GetDC();
GetDlgItem(IDC_SRCImage)->GetWindowRect(&m_rc);
ScreenToClient(&m_rc);
::SetStretchBltMode(m_pDC->GetSafeHdc(),COLORONCOLOR);
::StretchDIBits(m_pDC->GetSafeHdc(),
m_rc.left,m_rc.top,m_rc.Width(),m_rc.Height(),
0,0,m_pBmpInfo->bmiHeader.biWidth,m_pBmpInfo->bmiHeader.biHeight,
m_pSrcBuf,m_pBmpInfo,
DIB_RGB_COLORS,SRCCOPY);
5.读取进来的图像经过一系列的处理后,需要将处理后的图像进行保存。双击保存按钮可在源文件中添加消息响应函数void CBMP_RSYDlg::OnBnClickedButtonSave()
,并在消息响应函数中添加如下代码:
CFileDialog dlg(FALSE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"bmp(*bmp)|*.bmp||",this);
if (dlg.DoModal()!=IDOK)
{
MessageBox("图片保存失败!");
return;
}
m_strDstBmpPath = dlg.GetPathName();
CFile file;
file.Open(m_strDstBmpPath,CFile::modeCreate|CFile::modeWrite);
if (m_pBmpInfoDst->bmiHeader.biBitCount==8)
{
file.Write(m_pBmpFileHeaderDst,sizeof(BITMAPFILEHEADER));
file.Write(m_pBmpInfoDst,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256);
file.Write(m_pDstBuf,m_pBmpInfoDst->bmiHeader.biSizeImage);
file.Close();
}
else if (m_pBmpInfoDst->bmiHeader.biBitCount==24)
{
file.Write(m_pBmpFileHeaderDst,sizeof(BITMAPFILEHEADER));
file.Write(m_pBmpInfoDst,sizeof(BITMAPINFOHEADER));
file.Write(m_pDstBuf,m_pBmpInfoDst->bmiHeader.biSizeImage);
file.Close();
}
TIPS:
在进行文件的读取时,需要先申请一块内存,并将图片信息放在申请好的内存当中,当内存使用过后最好将内存释放,以免造成内存泄露。而在当进行批量图像的读取与显示的时候,每一张图像的读取都要进行内存的申请与释放,会造成线程的响应变慢,从而影响到整个进程。因此,最好的解决办法是提前申请好一个内存区域,在进程中不进行内存的释放,将图像进行循环读取并清除。这样就需要一块足够大的内存区域,一般是申请BYTE[2048*2048*4]
。
文件的读取与保存是常用功能,因此打开文件路径的函数需要牢记。