实验报告
学院:信息科学与工程学院
姓名: *******
班级:*********
学号:**********
指导老师:***
实验1 PhotoShop功能操作
一、实验目的
1、了解数码相机基本使用。
2、熟悉PHOTOSHOP在图像处理上的用途。
3、掌握PHOTOSHOP一些基本的图像操作。
二、实验内容
1、观察图像大小(宽与高像素)。
图像菜单中图像大小选项
图1,图像大小
2、改变图像大小。
在上述图像大小窗口改变数值就可以改变图像大小。
3、观察各处的RGB值、色度、亮度、饱和度的值。
将鼠标移动到图上各处,在右侧信息栏里可以看到RGB值。
图2,RGB值
再取颜色取样工具,右键点击图片,选择HSB即为色度亮度饱和度的值。
图3,HSB值
4、单独观察红色、绿色、蓝色分量图像。
右下角选择通道,选择不同通道即可观察红色,绿色,蓝色分量图像
图4,红色分量图
图5,绿色分量图
图6,蓝色分量图
5、将彩色图像转换为灰度图像,存盘后观察文件大小。
先选择图像→模式→灰度,选择扔掉
图7,灰度图像
然后另存为bmp格式的图像,可以看出文件大小变小了很多。
6、观察图像的直方图。
直接在右侧栏可观察到直方图。
图8,直方图
7、改变图像的亮度、对比度、饱和度,观察操作结果。
在图像中选择调整→亮度/对比度
即可调整然后观察效果
同样在调整中选择色相饱和度。即可调整饱和度
8、以不同阈值二值化图像。
在图像→调整→阈值,可以调整色阶,观察不同阈值二值化图像。
图9,观察不懂阈值二值化图像
实验2 Photoshop图像处理实验
一、实验目的
1、了解bmp图像的数据存储形式。
2、学习使用不同的滤波方法处理图像。
3、掌握PHOTOSHOP一些图像增强处理方法。
二、实验内容
1、打开一个bmp图像
2、自定义滤波器处理图像。
(1)滤波中选择自定义
图像有一定程度的模糊。常用的图像平滑模板有:
、、、、
选择第一种模板,得到
(2)从频谱的角度分析,图像的锐化类似于一个高通滤波器。常用的锐化模板有:
、
等。这两个模板又称为拉普拉斯模板。
选择第二个模板得到
(3)边缘查找又称为边缘检测,边缘是指周围像素灰度发生阶跃型或凸缘型变化的像素的集合。常用的边缘检测算子,包括Sobel、Prewitt、Krisch、Laplace算子等。这里采用Sobel
得到图像
3、练习使用模糊、锐化、涂抹、减淡和加深等工具进行图像的编辑。
这些工具都在右侧工具栏可以找到,比如说锐化工具和模糊工具
减淡加深工具:
实验3 图像处理编程实验
一、实验目的
1、熟悉VB或VC的基本编程方法。
2、了解bmp位图文件的结构。
3、掌握灰度直方图的原理及绘制过程。
二、实验内容
1、读取BMP位图文件
BMP 位图包括位图文件头结构BITMAPFILEHEADER 、位图信息头结构
BITMAPINFOHEADER、位图颜色表 RGBQUAD 和位图像素数据四部分。处理位图时要根据文件的这些结构得到位图文件大小、位图的宽、高、实现调色板、得到位图像素值等等。对于256 级灰度图像每个像素用 8bit 表示颜色的索引值,这里要注意的一点是在 BMP位图中,位图的每行像素值要填充到一个四字节边界,即位图每行所占的存储长度为四字节的倍数,不足时将多余位用0 填充。
在处理图像应用程序的文档类(CdibDoc.h)中声明如下宏及公有变量:
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)// 计算图像每行象素所占的字节数目
HANDLE m_hDIB;//存放位图数据的句柄
CPalette* m_palDIB;//指向调色板Cpalette类的指针
CSize m_sizeDoc; file:// 初始化视图的尺寸
根据BMP 位图文件的结构,操作 BMP 位图文件读入数据,重载了文挡类的
OnOpenDocument 函数如下:
BOOL CDibDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
CFile file;
CFileException fe;
if (!file.Open(lpszPathName, Cfile::modeRead | Cfile::shareDenyWrite, &fe))
{
AfxMessageBox("文件打不开");
return FALSE;
}//打开文件
DeleteContents();//删除文挡
BeginWaitCursor();
BITMAPFILEHEADER bmfHeader;//定义位图文件头结构
DWORD dwBitsSize;
HANDLE hDIB;
LPSTR pDIB;
BITMAPINFOHEADER *bmhdr;//指向位图信息头结构的指针
dwBitsSize = file.GetLength();// 得到文件长度
if (file.Read((LPSTR)&bmfHead er, sizeof(bmfHeader)) !=
sizeof(bmfHeader))
return FALSE;
if (bmfHeader.bfType != 0x4d42) file:// 检查是否为 BMP文件
return FALSE;
hDIB=(HANDLE) ::GlobalAlloc(GMEM_MOVEABLE |
GMEM_ZEROINIT, dwBitsSize);
file://申请缓冲区
if (hDIB == 0)
{
return FALSE;
}
pDIB = (LPSTR) ::GlobalLock((HGLOBAL)hDIB);
file://得到申请的缓冲区的指针
if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) !=
dwBitsSize - sizeof(BITMAPFILEHEADER) )
{
::GlobalUnlock((HGLOBAL)hDIB);
hDIB=NULL;
return FALSE;
}//读数据,包括位图信息、位图颜色表、图像像素的灰度值
bmhdr=(BITMAPINFOHEADER*)pDIB;// 为指向位图信息头结构的指针付值
::GlobalUnlock((HGLOBAL)hDIB);
if ((*bmhdr).biBitCount!=8) file:// 验证是否为8bit 位图
return FALSE;
m_hDIB=hDIB;
InitDIBData();
file://自定义函数,根据读入的数据得到位图的宽、高、颜色表
file:// 来得到初始化视的尺寸、生成调色板
EndWaitCursor();
SetPathName(lpszPathName);// 设置存储路径
SetModifiedFlag(FALSE); // 设置文件修改标志为FALSE
return TRUE;
}
为了将图像处理后所得到的像素值保存起来,重载了文档类的OnSaveDocument函数,
其具体实现如下:
BOOL CDibDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
CFile file;
CFileException fe;
BITMAPFILEHEADER bmfHdr; // 位图文件头结构
LPBITMAPINFOHEADER lpBI; file://指向位图信息结构的指针
DWORD dwDIBSize;
if (!file.Open(lpszPathName, Cfile::modeCreate |
Cfile::modeReadWrite | Cfile::shareExclusive, &fe))
{
AfxMessageBox("文件打不开");
}//打开文件
BOOL bSuccess = FALSE;
BeginWaitCursor();
lpBI = (LPBITMAPINFOHEADER) :: GlobalLock((HGLOB AL) m_hDIB);
if (lpBI == NULL)
return FALSE;
dwDIBSize = *(LPDWORD)lpBI + 256*sizeof(RGBQUAD);
// Partial Calculation
DWORD dwBmBitsSize;//BMP 文件信息结构所占的字节数
dwBmBitsSize=WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount))
*lpBI->biHeight;// 存储时位图所有像素所占的总字节数
dwDIBSize += dwBmBitsSize;
lpBI->biSizeImage = dwBmBitsSize; // 位图所有像素所占的总字节数
file://以下五句为文件头结构填充值
bmfHdr.bfType =0x4d42; // 文件为"BMP" 类型
bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);// 文件总长度
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize
+ 256*sizeof(RGBQUAD);
file://位图数据距问件头的偏移量
file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));//写文件头
file.WriteHuge(lpBI, dwDIBSize);
file://将位图信息(信息头结构、颜色表、像素数据)写入文件
::GlobalUnlock((HGLOBAL) m_hDIB);
EndWaitCursor();
SetModifiedFlag(FALSE); // back to unmodified
return TRUE;
}
灰度图像要正确显示,必须实现逻辑调色板和系统调色板,通过在主框架类中处理
Windows 定义的消息 WM_QUERYNEWPALETTE 、WM_PALETTECHANGED及视图类中
处理自定义消息 WM_DOREALIZE (该消息在主框架窗口定义如下:#define
WM_REALIZEPAL (WM_USER+100))来实现调色板的操作。
void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)
{ file:// 总实现活动视的调色板
CMDIFrameWnd::OnPaletteChanged(pFocusWnd);
CMDIChildWnd* pMDIChildWnd = MDIGetActive();
if (pMDIChildWnd == NULL)
return
CView* pView = pMDIChildWnd->GetActiveView();
ASSERT(pView != NULL);
SendMessageToDescendants(WM_DOREALIZE, (WPARAM)pView->m_hWnd);
file://通知所有子窗口系统调色板已改变
}
BOOL CMainFrame::OnQueryNewPalette()//提供实现系统调色板的机会
{
// 实现活动视的调色板
CMDIChildWnd* pMDIChildWnd = MDIGetActive();
if (pMDIChildWnd == NULL)
return FALSE; // no active MDI child frame (no new palette)
CView* pView = pMDIChildWnd->GetActiveView();
ASSERT(pView != NULL);
file://通知活动视图实现系统调色板
pView->SendMessage(WM_DOREALIZE, (WPARAM)pView->m_hWnd);
return TRUE;
}
LRESULT CDibView::OnDoRealize(WPARAM wParam, LPARAM)//实现系统调色板
{
ASSERT(wParam != NULL);
CDibDoc* pDoc = GetDocument();
if (pDoc->m_hDIB == NULL)
return 0L; // must be a new document
CPalette* pPal = pDoc->m_palDIB;
file://调色板的颜色表数据在InitDIBData() 函数中实现
if (pPal != NULL)
{
CMainFrame* pAppFrame = (CMainFr ame*) AfxGetApp()->m_pMainWnd;
ASSERT_KINDOF(CMainFrame, pAppFrame);
CClientDC appDC(pAppFrame);
CPalette* oldPalette = appDC.SelectPa lette(pPal, ((HWND)wP aram) != m_hWnd);
file://只有活动视才可以设为"FALSE" ,
// 即根据活动视的调色板设为"前景"调色板
if (oldPalette != NULL)
{
UINT nColorsChanged = appDC.RealizePalette();//实现系统调色板
if (nColorsChanged > 0)
pDoc->UpdateAllViews(NULL);// 更新视图
appDC.SelectPalette(oldPalette, TRUE);
file://将原系统调色板置为逻辑调色板
}
else
{
TRACE0("\SelectPalette failed in
CDibView::OnPaletteChanged\\n");
}
}
2、绘制灰度直方图。
下面的程序显示一幅图的灰度直方图。有两段程序,第一段统计出每个灰度的像素个数,存放在数组GrayTable[] 中,然后产生一个新的窗口,把统计结果显示出来。第二段程序就是该窗口的消息处理函数。要注意的是,由于各灰度出现的频率可能相差很大,所以如何将结果显示在有限的窗口范围内,是一个必须考虑的问题。我们这里的做法是,在所有出现的灰度中,统计出一个最大值 max 和一个最小值min,假设能显示的窗口最大坐标为 270,最小坐标为5 ,按成比例显示,这样,灰度出现的次数和显示坐标之间呈线形关系,设 a*grayhits+b=coordinate,其中 grayhits为灰度出现的次数,coordinate 为显示坐标,a 和b 为两个常数。我们将max 和min 代入,应该满足a*max+b=270 ; a*min+b=5
可以解得a=265/(max-min); b=270.0-a* max 。
int GrayTable[256];
int MaxGrayNum;
int MinGrayNum;
BOOL Histogram(HWND hWnd)
{
DWORD OffBits,BufSize;
LPBITMAPINFOHEADER lpImgData;
LPSTR lpPtr;
int x,y;
int grayindex;
HWND hPopupWnd;
int temp;
//计数器清零
for(grayindex=0;grayindex<256;grayindex++)
GrayTable[grayindex]=0;
//OffBits为到实际位图数据的偏移值
OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);
//BufSize 为缓冲区的大小
BufSize=bf.bfSize-sizeof(BITMAPFILEHEADER);
lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);
for(y=0;y for(x=0;x GrayTable[grayindex]++; // 对应的颜色计数值加 1 } } MaxGrayNum=0; MinGrayNum=65535; for(grayindex=0;grayindex<256;grayindex++){ temp=GrayTable[grayindex]; if(temp>MaxGrayNum) MaxGrayNum=temp; // 找到更大的了 if( (temp MinGrayNum=temp; // 找 到更小的了 } GlobalUnlock(hImgData); //产生新的窗口显示结果 hPopupWnd = CreateWindow ("PopupWindowClass", "Histogram Statistic Window",WS_OVERLAPPEDWINDOW,50,80,550,350, hWnd,NULL,ghInst,NULL); if (hPopupWnd){ ShowWindow (hPopupWnd, SW_SHOW); UpdateWindow (hPopupWnd); } return TRUE; } 下面是新窗口的消息处理函数 long FAR PASCAL PopupWndProc (HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; DWORD i; int xstart; static LOGPEN blp={PS_SOLID,1,1,RGB(0,0,255)}; // 蓝色画笔 HPEN bhp; //画笔句柄 float a,b,temp; char str[10]; //计算上面所说的 a,b的值 a=(float)(265.0 /( MaxGrayNum - MinGrayNum) ); b=(float) (270.0-a* MaxGrayNum); switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); bhp = CreatePenIndirect(&blp); SelectObject(hdc,bhp); MoveToEx(hdc,2,270,NULL); LineTo(hdc,518,270); // 先画一条水平线 xstart=2; for(i=0;i<256;i++){ MoveToEx(hdc,xstart,270,NULL); if (GrayTable[i]!=0) temp=(float)(a*GrayTable[i]+b); else temp=0.0f; //如果灰度出现的次数是零,则不画线 LineTo(hdc,xstart,270-(int)temp); // 画出该灰度的计数值 if (i%16 ==0){ //画出标尺,每 16 个一格 MoveToEx(hdc,xstart,270,NULL); LineTo(hdc,xstart,280); _itoa(i,str,10); TextOut(hdc,xstart,285,str,strlen(str)); } xstart+=2; } MoveToEx(hdc,xstart,270,NULL); LineTo(hdc,xstart,280); TextOut(hdc,xstart,285,"256",strlen("256")); EndPaint(hWnd,&ps); DeleteObject(bhp); break; default: break; } return DefWindowProc (hWnd, message, wParam, lParam); } 3、编程实现实验2中的图像处理方法。 void CDibView::OnMENUHighPass() { HANDLE data1handle; LPBITMAPINFOHEADER lpBi; CDibDoc *pDoc=GetDocument(); HDIB hdib; unsigned char *hData; unsigned char *data; hdib=pDoc->GetHDIB(); BeginWaitCursor(); lpBi=(LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib); hData=(unsigned char*)FindDIBBits((LPSTR)lpBi); pDoc->SetModifiedFlag(TRUE); data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight); data=(unsigned char*)Global Lock((HGLOBAL)data1handle); AfxGetApp()->BeginWaitCursor(); int i,j,s,t,ms=1; int sum=0,sumw=0; int mask[3][3]= 自定义的模板; for(i=0; ibiHeight; i++) for(j=0; jbiWidth; j++) { sumw=0; sum=0; for(s=(-ms); s<=ms; s++) for(t=(-ms); t<=ms; t++) if(((i+s)>=0) && ((j+t)>=0) && ((i+s)biHeight) && ((j+t)biWidth)) { sumw += mask[1+s][1+t]; sum+=*(hData+(i+s)*WIDTHBYTES(lpBi- >biWidth*8)+(j+t))*mask[1+s][1+t]; } if(sumw==0) sumw=1; sum/=sumw; if(sum>255)sum=255; if(sum<0)sum=0; *(data+i*WIDTHBYTES(lpBi->biWidth*8)+j)=sum; } for( j=0; jbiHeight; j++) for( i=0; ibiWidth; i++) *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi->biWidth*8)+j) ; AfxGetApp()->EndWaitCursor(); GlobalUnlock((HGLOBAL)hdib); GlobalUnlock(data1handle); EndWaitCursor(); Invalidate(TRUE); } 实验4 图像处理编程量测实验 一、实验目的 1、掌握Hough变换。 2、综合运用图像处理的各种操作,获取图像信息。 二、实验内容 a 平滑滤波 同实验三程序实现平滑滤波,滤波后效果图如下: b 边缘增强 同实验三程序实现边缘增强,增强后效果图如下: c Hough变换 BOOL Hough(HWND hWnd){ // 定义一个自己的直线结构 typedef struct{ int topx; // 最高点的 x 坐标 int topy; // 最高点的 y 坐标 int botx; // 最低点的 x 坐标 int boty; // 最低点的 y 坐标 }MYLINE; DWORD BufSize; LPBITMAPINFOHEADER lpImgData; LPSTR lpPtr; HDC hDc; LONG x,y; long i,maxd; int k; int Dist,Alpha; HGLOBAL hDistAlpha,hMyLine; int *lpDistAlpha; MYLINE *lpMyLine,*TempLine,MaxdLine; static LOGPEN rlp={PS_SOLID,1,1,RGB(255,0,0)}; HPEN rhp; if( NumColors!=256){ MessageBox(hWnd,"Must be a mono bitmap with grayscale palette!", "Error Message",MB_OK|MB_ICONEXCLAMATION); return FALSE; } // 计算最大距离 Dist=(int)(sqrt( (double)bi.biWidth*bi.biWidth+ (double)bi.biHeight*bi.biHeight)+0.5) ; Alpha=180 /2 ; //0 到 to 178 度,步长为 2 度 //为距离角度数组分配内存 if((hDistAlpha=GlobalAlloc(GHND,(DWO RD)Dist* Alpha * sizeof(int)))==NULL){ MessageBox(hWnd,"Error allo c memory! MB_ICONEXCLAMATION); return FALSE; } //为记录直线端点的数组分配内存 if((hMyLine=GlobalAlloc(GHND,(DWO RD)Dist*Alpha*sizeof(MYLINE)))==NULL){ GlobalFree(hDistAlpha); return FALSE; } //原图缓冲区的大小 BufSize=bf.bfSize-sizeof(BITMAPFILEHEADER); lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); lpDistAlpha=(int *)GlobalLock(hDistAlpha); lpMyLine=(MYLINE *)GlobalLock(hMyLine); for (i=0;i<(long)Dist*Alpha;i++){ TempLine=(MYLINE*)(lpMyLine+i); (*TempLine).boty=32767; //初始化最低点的 y 坐标为一个很大的值 } for (y=0;y lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes); for (x=0;x for (k=0;k<180;k+=2){ //计算距离 i i=(long)fabs((x*cos(k*PI/180.0)+y*sin(k*PI/180.0) )); //相应的数组元素加 1 *(lpDistAlpha+i*Alpha+k/2)=*(lpDistAlpha+i*Alpha+k/2)+1; TempLine=(MYLINE*)(lpMyLine+i*Alpha+k/2); if(y> (*TempLine).topy){ // 记录该直线最高点的 x,y 坐标 (*TempLine).topx=x; (*TempLine).topy=y; } if(y< (*TempLine).boty){ // 记录该直线最低点的 x,y 坐标 (*TempLine).botx=x; (*TempLine).boty=y; } } } maxd=0; for (i=0;i<(long)Dist*Alpha;i++){ TempLine=(MYLINE*)(lpMyLine+i); k=*(lpDistAlpha+i); if( k > maxd){ //找到数组元素中最大的,及相应的直线端点 maxd=k; MaxdLine.topx=(*TempLine).topx; MaxdLine.topy=(*TempLine).topy; MaxdLine.botx=(*TempLine).botx; MaxdLine.boty=(*TempLine).boty; } } hDc = GetDC(hWnd); rhp = CreatePenIndirect(&rlp); SelectObject(hDc,rhp); MoveToEx(hDc,MaxdLine.botx,MaxdLine.boty,NULL); //在两端点之间画一条红线用来标识 LineTo(hDc,MaxdLine.topx,MaxdLine.topy); DeleteObject(rhp); ReleaseDC(hWnd,hDc); //释放内存及资源 GlobalUnlock(hImgData); GlobalUnlock(hDistAlpha); GlobalFree(hDistAlpha); GlobalUnlock(hMyLine); GlobalFree(hMyLine); return TRUE; } d 求直线, 求交点, 得三角形高度、底边宽度、面积 求得三角形高度:158 像素 底边宽度:135 像素 面积:10665 像素2