数字图像处理
实验报告
实验一:
实验名称:彩色图转换成灰度图
实验任务:将 24 位真彩色 BMP 图像转化成 8 位 BMP 灰度图像
编程环境:MFC
设计思路:读入图像信息,将图像信息放入内存中。重新申请内存空间存放 8 位 256 级灰度
图像。并设置一个调色板,用来存放 256 级灰度级,以便于生成灰度图像时用的颜色信息。
用指针得到每个像素点的颜色值,并用原来 24 位的颜色转换成 8 位的灰度级,放入新的图
像信息中。最后保存灰度图。
主要模块:
主函数:
确定要打开和保存的文件名,调用转换函数和保存图片函数,最后释放指针
转换函数:
BYTE* ConvertTo8Bit(CString strFileName, DWORD *dwFileLength, BYTE
*lpNewBmpData)
将指定的文件读入,取得 BMP 图像的文件头,文件信息头,文件大小,读
取文件数据信息。重新申请空间存放新图像的信息,设置新图像的文件头的信息,并设置一
个它的颜色表,存放 256 级灰度。将得到的原图的每个像素点的颜色值转换成新图像的灰度
值,存放在新的头像信息中。
保存函数:
BOOL SaveFile(CString strFileName, DWORD dwFileLength)
将新的图像信息写入,先写位图头信息,再把实际数据写入。
void CMyDlg::OnOK()
{
CString
strOpenFileName,strSaveFileName;
strOpenFileName="24.bmp";
strSaveFileName="灰度.bmp";
DWORD dwFileLength;
lpNewBmpInfo
=
(BITMAPINFO*)ConvertTo8Bit( strOpenFile
Name, &dwFileLength, lpNewBmpData);
if( !lpNewBmpInfo ){
printf( "转换出错,程序退出!\n");
return ;}
if(!SaveFile(strSaveFileName,
dwFileLength) ){
printf( "保存文件出错!" );
return ;}
if( lpNewBmpData != NULL)
delete []lpNewBmpData;
if( lpNewBmpInfo != NULL )
delete []lpNewBmpInfo;
if( lpOldBmp != NULL )
delete []lpOldBmp;}
BYTE*
CMyDlg::ConvertTo8Bit(CString
strFileName, DWORD *dwFileLength, BYTE
*lpNewBmpData)
{
CDC *pDC=m_image.GetDC();
CRect m_rect;
m_image.GetClientRect(m_rect);
if( lpNewBmpData != NULL ){
delete []lpNewBmpData;
lpNewBmpData = NULL;}
hFile
HANDLE
= ::CreateFile(strFileName,GENERIC_READ,
FILE_SHARE_READ,NULL,OPEN_EXISTI
NG,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile == 0){
printf("不能打开文件,请重新选择!\n");
return NULL;}
DWORD dwWriteNum;
//
BITMAPFILEHEADER Bmp_file_head;
文件头
ReadFile(hFile,&Bmp_file_head,14,&dwWrit
eNum,NULL);//读取文件头,共 14 个字节
if((Bmp_file_head.bfType!='MB')||(dwWriteN
um != sizeof(BITMAPFILEHEADER))){
printf("不是 BMP 位图文件或数据有误!\n");
return NULL;}
*dwFileLength=GetFileSize(hFile,NULL)-siz
eof(BITMAPFILEHEADER); // 获 取 文 件 的
长度
BYTE *lpOldBmp;
lpOldBmp= new BYTE[*dwFileLength];
//存放原 24 位位图像,包括图像的信息头、
调色板和像素数据
ReadFile(hFile,lpOldBmp,*dwFileLengt
//读取图像数据
h,&dwWriteNum,NULL);
BYTE*lpOldBmpData = lpOldBmp +
//指
sizeof(BITMAPINFOHEADER) ;
向图像数据的实际位置,其调色板为 0
BITMAPINFO*lpOldBmpInfo
=
(BITMAPINFO*)lpOldBmp;
if(lpOldBmpInfo->bmiHeader.biBitCount!=
24){
printf( "此图像非 24 位位图!");
return NULL;}
Int nScanWidth;//转换后其每行扫描宽度
int nLineWidth;//将其转换成 8 位位图后
每行宽度(即每行字节数)
nSrcWidth,nSrcHeight;
int
height=nSrcHeight=lpOldBmpInfo->bmi
Header.biHeight;
//原 24 位位图高度
1]*0.587+color[0]*0.114);
width=nSrcWidth=lpOldBmpInfo->bmiH
pDC->SetPixel(j,height-i,RGB(dwColor
eader.biWidth;
//原 24 位位图宽度
nLineWidth = nSrcWidth*3/4*4;
if(nLineWidthbmiHeader=lpOldBmpI
nfo->bmiHeader;
lpNewBmpInfo->bmiHeader.biBitCount=8;
//数据起始位置为原位图信息头起始+
位图信息头大小+彩色表大小
lpNewBmpData=(BYTE*)lpNewBmpInfo+si
zeof(BITMAPINFOHEADER)+256*
sizeof(RGBQUAD);
i,j;
int
//为其相应的彩色表赋值
for(i=0;i<256;i++)
lpNewBmpInfo->bmiColors[i].rgbRed=i;
{
lpNewBmpInfo->bmiColors[i].rgbGreen=i;
lpNewBmpInfo->bmiColors[i].rgbBlue=i;
lpNewBmpInfo->bmiColors[i].rgbReserved=0;
//保留位}
for(i=0;i255)
dwColorTemp=255;
if( dwColorTemp< 0 )
dwColorTemp = 0;
lpNewBmpData[i*nScanWidth+j]=(BYT
}
}
E)dwColorTemp;
lpNewBmpData[nScanWidth*nSrcHeight]=0;
lpNewBmpData[nScanWidth*nSrcHeight+1]
=0;
if( !CloseHandle( hFile ) )
printf("关闭文件时失败");
return (BYTE*)lpNewBmpInfo;}
CMyDlg::SaveFile(CString
BOOL
strFileName,DWORD dwFileLength)
{HANDLE
=
CreateFile( strFileName, GENERIC_WRITE,
FILE_SHARE_WRITE,NULL,CREATE_AL
WAYS,FILE_ATTRIBUTE_NORMAL,
NULL);
hSaveFile
if( !hSaveFile ){
printf( "创建文件出错\n");
return FALSE;}
DWORD dwWriteNum;
BITMAPFILEHEADER BFH;
BFH.bfType = 'MB';
BFH.bfSize
=
dwFileLength
+
sizeof(BITMAPFILEHEADER);
BFH.bfOffBits=sizeof(BITMAPFILEHEADE
R) + sizeof(BITMAPINFOHEADER) + 256*
sizeof(RGBQUAD); //256 为 调 色 表 颜 色 数
(0-255)
BFH.bfReserved1 = BFH.bfReserved2 = 0;
//写位图头信息
WriteFile(
hSaveFile,
sizeof(BITMAPFILEHEADER),
&dwWriteNum, NULL);
&BFH,
//写实际数据
WriteFile( hSaveFile,
lpNewBmpInfo,
dwFileLength, &dwWriteNum, NULL);
CloseHandle( hSaveFile );
return TRUE;}
实验前:(24 位真彩图)
实验后:(8 位灰度图)
实验二:
实验名称:图片颜色去反。
实验任务:将一张 8 位的灰度图,颜色取反,产生底片效果。
设计思路:将灰度图的文件头和数据信息读入内存,然后将每个像素的值取反,然后将文件
头和新的像素值写入另一个图片文件中。
主要模块:
主函数:读入图片名称,调用转换函数和保存函数。
转换函数:
BYTE* Reverse(DWORD *dwFileLength, BYTE *lpNewBmpData)
将指定的文件读入,取得 BMP 图像的文件头,文件信息头,文件大小,
读取文件数据信息。重新申请空间存放新图像的信息,设置新图像的文件头的信息,并设置
一个它的颜色表,存放 256 级灰度。将得到的原图的每个像素点的颜色值转换成新图像的灰
度值,存放在新的头像信息中。
保存函数:
BOOL SaveFile(CString strFileName, DWORD dwFileLength)
将新的图像信息写入,先写位图头信息,再把实际数据写入。
void CMyDlg::OnButton1()
{
DWORD dwFileLength;
CString strSaveFileName="底片.bmp";
lpNewBmpInfo
=
(BITMAPINFO*)Reverse(&dwFileLength,
lpNewBmpData);
if( !lpNewBmpInfo ){
printf( "转换出错,程序退出!\n");
return ;
}
if(
// 位图信息头
if(fileheader.bfType!=0x4D42){
pDC->TextOut(100,200," 无 位 图 文
件请选择位图文件");
fclose(fp);
return NULL;
}
fread(&info.bmiHeader,sizeof(BITMAPINFO
HEADER),1,fp);
// 颜色表
long width=info.bmiHeader.biWidth;
//
位图的宽度,以像素为单位
!SaveFile(
strSaveFileName,
long
height=info.bmiHeader.biHeight;
dwFileLength) ){
printf( "保存文件出错!" );
return ;
}
if( lpNewBmpData != NULL)
delete []lpNewBmpData;
if( lpNewBmpInfo != NULL )
delete []lpNewBmpInfo;
if( lpOldBmp != NULL )
delete []lpOldBmp;}
CMyDlg::Reverse(DWORD
BYTE*
*dwFileLength, BYTE *lpNewBmpData)
{if( lpNewBmpData != NULL ){
delete []lpNewBmpData;
lpNewBmpData = NULL;
}
CDC *pDC=m_image2.GetDC();
CRect m_rect;
m_image2.GetClientRect(m_rect);
FILE *fp=fopen("image8.bmp","r");
if(fp==NULL){
pDC->TextOut(100,200,"no file found");
return NULL;
// 位图的高度,以像素为单位
int nScanWidth;//转换后其每行扫描宽度
int nLineWidth;
//将其转换成 8 位
位图后每行宽度(即每行字节数)
nLineWidth = width*3/4*4;
if(nLineWidthbmiHeader=info.bmiHeader;
lpNewBmpInfo->bmiHeader.biBitCount=8;
//数据起始位置为原位图信息头起
始+位图信息头大小+彩色表大小
lpNewBmpData
(BYTE*)lpNewBmpInfo
sizeof(BITMAPINFOHEADER)
sizeof(RGBQUAD);
+
//为其相应的彩色表赋值
for(int i=0;i<256;i++) {
=
+
256*
lpNewBmpInfo->bmiColors[i].rgbRed=i;
lpNewBmpInfo->bmiColors[i].rgbGreen=i;
lpNewBmpInfo->bmiColors[i].rgbBlue=i;
lpNewBmpInfo->bmiColors[i].rgbReserved=0;
//保留位}
if(info.bmiHeader.biBitCount==8){
int pitch;
if(width%4==0){
pitch=width;
}else{
}
}
}
}
lpNewBmpData[nScanWidth*height]=0;
lpNewBmpData[nScanWidth*height+1]=0;
if( !CloseHandle( fp ) )
printf("关闭文件时失败");
return (BYTE*)lpNewBmpInfo;
}
BOOL
strFileName,DWORD dwFileLength)
{
CMyDlg::SaveFile(CString
HANDLE
=
CreateFile( strFileName, GENERIC_WRITE,
FILE_SHARE_WRITE,
hSaveFile
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
pitch=width+4-width%4;}
if( !hSaveFile ){
RGBQUAD quad[256];
fseek(fp,fileheader.bfOffBits-sizeof(RGBQU
AD)*256,0);
fread(quad,sizeof(RGBQUAD)*256,1,fp);
if(height>0){
//height>0 表示图片颠倒
for(i=0;iSetPixel(j,height-i,RGB(r,g,b));
lpNewBmpData[i*nScanWidth+j]=(BYTE)R
GB(r,g,b); }}}
else{for(int i=0;i<0-height;i++){
for(int j=0;jSetPixel(j,i,RGB(r,g,b));
lpNewBmpData[i*nScanWidth+j]=(BYT
E)RGB(r,g,b);
实验前(灰度图)
BFH.bfOffBits
=
sizeof(BITMAPFILEHEADER)
+
sizeof(BITMAPINFOHEADER)
256*
sizeof(RGBQUAD); //256 为 调 色 表 颜 色 数
(0-255)
BFH.bfReserved1 = BFH.bfReserved2 = 0;
+
//写位图头信息
WriteFile(
hSaveFile,
sizeof(BITMAPFILEHEADER),
&dwWriteNum, NULL);
&BFH,
//写实际数据
WriteFile( hSaveFile,
lpNewBmpInfo,
dwFileLength, &dwWriteNum, NULL);
CloseHandle( hSaveFile );
return TRUE;
}
实验后(底片效果)
实验三:
实验题目:将 8 位灰度图均衡化(直方图)
实验任务:将 8 为的灰度图利用直方图的得到的效果,进行均衡化处理,是颜色分布均衡
设计思路:读入文件头和数据信息,共有 256 个灰度级,首先计算各级灰度的比例,将每个
级进行摄入运算,再通过舍入后的信息计算对应每个比例的像素个数,最后写入新的图片。
主要模块:
void CMyDlg::OnButton2()
{
FILE *f=fopen("image8.bmp","rb");
fseek(f,0,0);//移动到开头
//----------读 BMP 文件头
BITMAPFILEHEADER
*bmph=new
CDC *pDC=m_image2.GetDC();
CRect m_rect;
m_image2.GetClientRect(m_rect);
BITMAPFILEHEADER();
if(fread((char*)bmph,sizeof(BITMAPFIL
for(i=0;i<255;i++)
EHEADER),1,f)==NULL){
nh[i]=0.0;
printf("File read error");
return;
}
//-----------读 BMP 信息头
BITMAPINFO
*bmpi=new
BITMAPINFO();
if(fread((char*)bmpi,sizeof(BITMAPINF
O),1,f)==NULL){
printf("File read error2");
return;
}
//--------------读彩色表
long
*c=new
long[bmph->bfOffBits-sizeof(BITMAPFILE
HEADER)-sizeof(BITMAPINFO)];
fread((char*)c,bmph->bfOffBits-sizeof(BITM
APFILEHEADER)-sizeof(BITMAPINFO),1,f)
;
if(f==NULL //*判断文件是否打开成功
{
printf("File open error");
return;
}
int i,j,wc;
long
long *count=new long[255]; //每一灰度
级的象素数量统计
for(i=0;i<255;i++)
count[i]=0;
for(i=0;ibmiHeader.biWidth;
int height=bmpi->bmiHeader.biHeight;
//用于循环变量
if(width%4==0)//因为 BMP 图像 4 字节对齐
N=bmph->bfSize-
wc=width/4*4;
bmph->bfOffBits;//象素总数
else
unsigned char *image=new unsigned
wc=(width/4+1)*4;
char[N]; //位图矩阵
unsigned char *newimage=new unsigned
char[N];//变换后的位图矩阵
fread(image,N,1,f);//读入位图矩阵
//---------直方图数列初始化
//------直方图数列用来存储正规化后的灰度
double *h=new double[255];//255 个 灰
度级,保存原始图像正规化灰度直方图数据
for(i=0;i<255;i++)
h[i]=0.0;
double *nh=new double[255];//255 个灰
度级,保存变换后的图像正规化灰度直方图
处理前(灰度图):
}
long a;
long pos=0;
for( i=0;iSetPixel(j,height-i,RGB(a,a,a));
pos++;
}
}
if( !CloseHandle( f ) )
printf("关闭文件时失败");