【数字图像处理】七.MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化详解
? ? ? ?本文主要講述基于VC++6.0 MFC圖像處理的應(yīng)用知識,主要結(jié)合自己大三所學(xué)課程《數(shù)字圖像處理》及課件進(jìn)行講解,主要通過MFC單文檔視圖實(shí)現(xiàn)顯示BMP圖像增強(qiáng)處理,包括圖像普通平滑、高斯平滑、不同算子的圖像銳化知識。希望該篇文章對你有所幫助,尤其是初學(xué)者和學(xué)習(xí)圖像處理的學(xué)生。
? ? ? ?【數(shù)字圖像處理】一.MFC詳解顯示BMP格式圖片
? ? ? ?【數(shù)字圖像處理】二.MFC單文檔分割窗口顯示圖片
? ? ? ?【數(shù)字圖像處理】三.MFC實(shí)現(xiàn)圖像灰度、采樣和量化功能詳解
? ? ? ?【數(shù)字圖像處理】四.MFC對話框繪制灰度直方圖
? ? ? ?【數(shù)字圖像處理】五.MFC圖像點(diǎn)運(yùn)算之灰度線性變化、灰度非線性變化、閾值化和均衡化處理詳解
? ? ? ?【數(shù)字圖像處理】六.MFC空間幾何變換之圖像平移、鏡像、旋轉(zhuǎn)、縮放詳解
? ? ? ??免費(fèi)資源下載地址:
? ? ? ??http://download.csdn.net/detail/eastmount/8785591
?
一. 圖像增強(qiáng)簡介
? ? ? ? 圖像增強(qiáng)是對圖像進(jìn)行處理,使其比原始圖像更適合于特定的應(yīng)用,它需要與實(shí)際應(yīng)用相結(jié)合。對于圖像的某些特征如邊緣、輪廓、對比度等,圖像增強(qiáng)是進(jìn)行強(qiáng)調(diào)或銳化,以便于顯示、觀察或進(jìn)一步分析與處理。圖像增強(qiáng)的方法是因應(yīng)用不同而不同的,研究內(nèi)容包括:(參考課件和左飛的《數(shù)字圖像處理》)
?
二. 圖像平滑
? ? ? ? 圖像平滑是一種區(qū)域增強(qiáng)的算法,平滑算法有鄰域平均法、中指濾波、邊界保持類濾波等。在圖像產(chǎn)生、傳輸和復(fù)制過程中,常常會因?yàn)槎喾矫嬖蚨辉肼暩蓴_或出現(xiàn)數(shù)據(jù)丟失,降低了圖像的質(zhì)量(某一像素,如果它與周圍像素點(diǎn)相比有明顯的不同,則該點(diǎn)被噪聲所感染)。這就需要對圖像進(jìn)行一定的增強(qiáng)處理以減小這些缺陷帶來的影響。
? ? ? ?1.簡單平滑-鄰域平均法
? ? ? ? 圖像簡單平滑是指通過鄰域簡單平均對圖像進(jìn)行平滑處理的方法,用這種方法在一定程度上消除原始圖像中的噪聲、降低原始圖像對比度的作用。它利用卷積運(yùn)算對圖像鄰域的像素灰度進(jìn)行平均,從而達(dá)到減小圖像中噪聲影響、降低圖像對比度的目的。
? ? ? ? 但鄰域平均值主要缺點(diǎn)是在降低噪聲的同時使圖像變得模糊,特別在邊緣和細(xì)節(jié)處,而且鄰域越大,在去噪能力增強(qiáng)的同時模糊程度越嚴(yán)重。
? ? ? ? 2.高斯平滑
? ? ? ? 為了克服簡單局部平均法的弊端(圖像模糊),目前已提出許多保持邊緣、細(xì)節(jié)的局部平滑算法。它們的出發(fā)點(diǎn)都集中在如何選擇鄰域的大小、形狀和方向、參數(shù)加平均及鄰域各店的權(quán)重系數(shù)等。
? ? ? ? 圖像高斯平滑也是鄰域平均的思想對圖像進(jìn)行平滑的一種方法,在圖像高斯平滑中,對圖像進(jìn)行平均時,不同位置的像素被賦予了不同的權(quán)重。
? ? ? ? 在圖像簡單平滑中,算法利用卷積模板逐一處理圖像中每個像素,這一過程可以形象地比作對原始圖像的像素一一進(jìn)行過濾整理,在圖像處理中把鄰域像素逐一處理的算法過程稱為濾波器。平滑線性濾波器的工作原理是利用模板對鄰域內(nèi)像素灰度進(jìn)行加權(quán)平均,也稱為均值濾波器。
? ? ? ? 高斯平滑與簡單平滑不同,它在對鄰域內(nèi)像素進(jìn)行平均時,給予不同位置的像素不同的權(quán)值,下圖的所示的3*3和5*5領(lǐng)域的高斯模板。
? ? ? ? 模板越靠近鄰域中心位置,其權(quán)值越高。在圖像細(xì)節(jié)進(jìn)行模糊時,可以更多的保留圖像總體的灰度分布特征。下圖是常用的四個模板和matlab代碼實(shí)現(xiàn):
? ? ? ? 代碼如下:
I1 = imread('blood1.tif'); I=imnoise(I1,‘salt & pepper’,0.04); %對圖像加椒鹽噪聲 imshow(I); h1= [0.1 0.1 0.1; 0.1 0.2 0.1; 0.1 0.1 0.1]; %定義4種模板 h2=1/16.*[1 2 1;2 4 2;1 2 1]; h3=1/8.*[1 1 1;1 0 1;1 1 1]; h4=1/2.*[0 1/4 0;1/4 1 1/4;0 1/4 0]; I2=filter2(h1,I); %用4種模板進(jìn)行濾波處理 I3=filter2(h2,I); I4=filter2(h3,I); I5=filter2(h4,I); figure,imshow(I2,[]) %顯示處理結(jié)果 figure,imshow(I3,[]) figure,imshow(I4,[]) figure,imshow(I5,[])? ? ? ? 運(yùn)行效果如下圖所示:
? ? ? ??3.中值濾波
? ? ? ? 在使用鄰域平均法去噪的同時也使得邊界變得模糊。而中值濾波是非線性的圖像處理方法,在去噪的同時可以兼顧到邊界信息的保留。
? ? ? ? 選一個含有奇數(shù)點(diǎn)的窗口W,將這個窗口在圖像上掃描,把窗口中所含的像素點(diǎn)按灰度級的升或降序排列,取位于中間的灰度值來代替該點(diǎn)的灰度值。
? ? ? ? 例如選擇濾波的窗口如下圖,是一個一維的窗口,待處理像素的灰度取這個模板中灰度的中值,濾波過程如下:
? ? ? ? 常用的窗口還有方形、十字形、圓形和環(huán)形。不同形狀的窗口產(chǎn)生不同的濾波效果,方形和圓形窗口適合外輪廓線較長的物體圖像,而十字形窗口對有尖頂角狀的圖像效果好。
? ? ? ? 中值濾波對于消除孤立點(diǎn)和線段的干擾十分有用,尤其是對于二進(jìn)噪聲,但對消除高斯噪聲的影響效果不佳。對于一些細(xì)節(jié)較多的復(fù)雜圖像,可以多次使用不同的中值濾波。matlab實(shí)現(xiàn)參考:http://blog.csdn.net/timidsmile/article/details/6904381
? ? ? ? 4.邊界保持類濾波
? ? ? ? K近鄰均值濾波器(KNNF)是指在m*m的窗口中,屬于同一集合類的像素,它們的灰度值將高度相關(guān)。被處理的像素(對應(yīng)于窗口中心的像素)可以用窗口內(nèi)與中心像素灰度最接近的k個近鄰像素的平均灰度來替代。步驟如下:
? ? ? ? (1).作一個m*m的作用模板
? ? ? ? (2).在其中選擇K個與待處理像素的灰度差為最小的像素
? ? ? ? (3).用這K個像素的灰度均值替換掉原來的值
? ? ? ? 在K近旁均值濾波器(KNNMF)中,不選K個鄰近像素的平均灰度來替代,而選K個鄰近像素的中值灰度來替代,上圖中2,3,3中選擇3即可。
? ? ? ? 下面介紹具體MFC VC++6.0代碼實(shí)現(xiàn)過程。
?
三. 圖像平滑代碼實(shí)現(xiàn)
? ? ? ? 第一步:在資源視圖的Menu中添加子菜單“圖像增強(qiáng)”,然后添加“圖像平滑”四個選項(xiàng)如下圖所示:
? ? ? ? 第二步:打開類向?qū)?#xff0c;在ImageProcessingView類中添加相應(yīng)的四個實(shí)現(xiàn)函數(shù):
? ? ? ? 第三步:就是具體的平滑實(shí)現(xiàn)函數(shù)。
? ? ? ? 1.普通平滑 模板一
? ? ? ? 該算法采用的模板如下:
? ? ? ? 代碼如下:
/**************************************************第九章--圖像增強(qiáng) 圖像平滑 普通平滑 模板float H1[3][3]={{1.0/10,1.0/10,1.0/10}, //模板一:系數(shù)1/10{1.0/10,2.0/10,1.0/10},{1.0/10,1.0/10,1.0/10}};float H2[3][3]={{1.0/16,2.0/16,1.0/16}, //模板二:系數(shù)1/16{2.0/16,4.0/16,2.0/16},{1.0/16,2.0/16,1.0/16}};float H3[3][3]={{1.0/8,1.0/8,1.0/8}, //模板三:系數(shù)1/8,此種情況為把點(diǎn)轉(zhuǎn)為空心矩形{1.0/8,0.0/8,1.0/8},{1.0/8,1.0/8,1.0/8}};float H4[3][3]={{0.0,1.0/8,0.0}, //模板四:系數(shù)乘數(shù)據(jù)后的矩陣{1.0/8,1.0/2,1.0/8},{0.0,1.0/8,0.0}};/**************************************************/void CImageProcessingView::OnTxzqPtph1() {if(numPicture==0) {AfxMessageBox("載入圖片后才能圖像增強(qiáng)(平滑)!",MB_OK,0);return;}AfxMessageBox("圖像增強(qiáng)(平滑)!選取的模板為:普通平滑 模板一",MB_OK,0);/******************************************************************//* 圖想平滑的算法: /* 1.定義常用的四個模板,它們的維數(shù)均為3,矩陣的個數(shù)均為9個數(shù)據(jù) /* 2.它的思想是把一個點(diǎn)分散到這周圍的9個點(diǎn)上,這樣使圖像更模糊 /* 3.通過卷積計(jì)算圍繞該點(diǎn)的矩陣像素和,計(jì)算其平均值(除9)賦值給點(diǎn) /* 4.模塊不同,處理后的圖像也各不相同 /******************************************************************//*第一步:先定義數(shù)據(jù)模板*/int HWS=3; //模板維數(shù):此四個模板均為3維的float H1[3][3]={{1.0/10,1.0/10,1.0/10}, //模板一:系數(shù)1/10{1.0/10,2.0/10,1.0/10},{1.0/10,1.0/10,1.0/10}};//打開臨時的圖片F(xiàn)ILE *fpo = fopen(BmpName,"rb");FILE *fpw = fopen(BmpNameLin,"wb+");fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo); fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo); fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);fread(m_pImage,m_nImage,1,fpo);//new和delete有效的進(jìn)行動態(tài)內(nèi)存的分配和釋放unsigned char *ImageSize; ImageSize = new unsigned char[m_nImage]; float red,green,blue;int X,Y; //一維坐標(biāo)轉(zhuǎn)換為二維坐標(biāo)int TR,TG,TB; //記錄紅綠藍(lán)坐標(biāo)位置//圖像增強(qiáng):平滑 它要獲取源圖像周圍9個點(diǎn)的矩陣乘以模板9個點(diǎn)的矩陣,故一維圖像轉(zhuǎn)二維for(int i=0; i<m_nImage ; i=i+3 ){//原圖:一維矩陣轉(zhuǎn)換為二維矩陣X=(i/3)%m_nWidth; //圖像在X列Y=(i/3)/m_nWidth; //圖像在Y行//賦值為黑色,相當(dāng)于清零red=green=blue=0;//對圖像進(jìn)行像素求和并取平均值 HWS維數(shù)for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ ) //第j行{for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ ) //第k列{if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight ) //防止越界{ //模板一 進(jìn)行模板平均,把該點(diǎn)像素分散到四周TR=j*m_nWidth*3+k*3; red+=H1[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);TG=j*m_nWidth*3+k*3+1;green+=H1[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);TB=j*m_nWidth*3+k*3+2;blue+=H1[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);}}}//對新圖像賦值ImageSize[i]=(unsigned char)(red);ImageSize[i+1]=(unsigned char)(green);ImageSize[i+2]=(unsigned char)(blue);}fwrite(ImageSize,m_nImage,1,fpw); fclose(fpo);fclose(fpw);numPicture = 2;level=400;Invalidate(); }? ? ? ? 運(yùn)行效果如圖所示,圖像平滑模糊了,但效果不是很好。
? ? ? ? 其中實(shí)現(xiàn)的具體原理如下:
? ? ? ? 首先將圖像像素矩陣轉(zhuǎn)換為(X,Y)的二維矩陣進(jìn)行操作,同時獲取(X,Y)坐標(biāo)為中心的3*3矩陣,再通過它與3*3模板進(jìn)行像素平均操作,就是兩個3*3矩陣互乘。需要注意的是矩陣一個格子是RGB三字節(jié)(24位BMP),同時獲取該中心點(diǎn)位置時,通過兩層循環(huán)for(k=n-1;k<=n+1;k++)實(shí)現(xiàn)獲取矩陣中九個點(diǎn)的像素。最后對該點(diǎn)(X,Y)的RGB進(jìn)行賦值操作即可。
? ? ? ?2.普通平滑 模板二
? ? ? ? 該算法采用的模板如下:
? ? ? ? 代碼如下:
void CImageProcessingView::OnTxzqPtph2() {if(numPicture==0) {AfxMessageBox("載入圖片后才能圖像增強(qiáng)(平滑)!",MB_OK,0);return;}AfxMessageBox("圖像增強(qiáng)(平滑)!選取的模板為:普通平滑 模板二",MB_OK,0);/*第一步:先定義數(shù)據(jù)模板*/int HWS=3;float H2[3][3]={{1.0/8,1.0/8,1.0/8}, //模板三:系數(shù)1/8 此種情況為把點(diǎn)轉(zhuǎn)為空心矩形{1.0/8,0.0/8,1.0/8},{1.0/8,1.0/8,1.0/8}};//打開臨時的圖片F(xiàn)ILE *fpo = fopen(BmpName,"rb");FILE *fpw = fopen(BmpNameLin,"wb+");fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo); fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);//重點(diǎn):圖像的每行像素都必須是4的倍數(shù):1*1的圖像為 r g b 00H int num; //記錄每行多余的圖像素?cái)?shù)個數(shù) int sfSize; //補(bǔ)齊后的圖像大小 if(m_nWidth*3%4!=0) { num=(4-m_nWidth*3%4); sfSize=(m_nWidth*3+num)*m_nHeight; //每行多number個 } else { num=0; sfSize=m_nWidth*m_nHeight*3; } /*更改文件頭信息 定義臨時文件頭結(jié)構(gòu)變量*/ BITMAPFILEHEADER bfhsf; BITMAPINFOHEADER bihsf; bfhsf=bfh; bihsf=bih; bfhsf.bfSize=sfSize+54; fwrite(&bfhsf,sizeof(BITMAPFILEHEADER),1,fpw); fwrite(&bihsf,sizeof(BITMAPINFOHEADER),1,fpw); fread(m_pImage,m_nImage,1,fpo); //new和delete有效的進(jìn)行動態(tài)內(nèi)存的分配和釋放unsigned char *ImageSize; ImageSize = new unsigned char[sfSize]; float red,green,blue;int X,Y; //一維坐標(biāo)轉(zhuǎn)換為二維坐標(biāo)int TR,TG,TB; //記錄紅綠藍(lán)坐標(biāo)位置 int countWidth=0; //記錄每行的像素個數(shù),滿行時變回0 int place=0; //建立臨時坐標(biāo) 記錄起始坐標(biāo)(0,0)平移過來的位置 //圖像增強(qiáng) 平滑for(int i=0; i<m_nImage; ){//原圖一維矩陣轉(zhuǎn)換為二維矩陣X=(i/3)%m_nWidth; //圖像在X列Y=(i/3)/m_nWidth; //圖像在Y行//賦值為黑色,相當(dāng)于清零red=green=blue=0;//對圖像進(jìn)行像素求和并取平均值 HWS維數(shù)for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ ) //第j行{for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ ) //第k列{if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight ) //防止越界{ //模板二 進(jìn)行模板平均,把該點(diǎn)像素分散到四周TR=j*m_nWidth*3+k*3; red+=H2[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);TG=j*m_nWidth*3+k*3+1;green+=H2[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);TB=j*m_nWidth*3+k*3+2;blue+=H2[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);}}}//對新圖像賦值//通過變量place賦值變換后的圖像 i始終指向原圖3的倍數(shù) 為了補(bǔ)0而添加place變量ImageSize[place]=(unsigned char)(red);i++; place++;ImageSize[place]=(unsigned char)(green);i++; place++;ImageSize[place]=(unsigned char)(blue);i++; place++;countWidth=countWidth+3;if(countWidth==m_nWidth*3) { if(num==0) { countWidth=0; place=Y*m_nWidth*3;} else //num為補(bǔ)0 { for(int n=0;n<num;n++) { ImageSize[place]=0; place++; } countWidth=0; place=Y*(m_nWidth*3+num); //重點(diǎn) 添加Num } } }fwrite(ImageSize,sfSize,1,fpw); fclose(fpo);fclose(fpw);numPicture=2;level=400;Invalidate(); }? ? ? ? 你可能注意到了,在圖像處理過程中,如果每行的字節(jié)數(shù)不是4的倍數(shù),可能會出現(xiàn)斜線之類的處理BUG,所以需要手動補(bǔ)0籌齊4的倍數(shù),代碼中補(bǔ)0后運(yùn)行效果如下圖所示,我也一直沒找到原因,可能是思想和深度還沒有達(dá)到,以后有機(jī)會在解決吧!同時后面的算法都不準(zhǔn)備再進(jìn)行補(bǔ)0處理,主要講述算法的思想!
? ? ? ? ?3.高斯平滑
? ? ? ? ?采用的模板如下:
? ? ? ? 代碼如下圖所示:
//高斯平滑 void CImageProcessingView::OnTxzqGsph() {if(numPicture==0) {AfxMessageBox("載入圖片后才能圖像增強(qiáng)(平滑)!",MB_OK,0);return;}AfxMessageBox("圖像增強(qiáng)(平滑)!選取的模板為:高斯平滑",MB_OK,0);/*第一步:先定義數(shù)據(jù)模板*/int HWS=3; //模板維數(shù)為3維float H[3][3]={{1.0/16,2.0/16,1.0/16}, //高斯模板 系數(shù)1/16{2.0/16,4.0/16,2.0/16},{1.0/16,2.0/16,1.0/16}};//打開臨時的圖片F(xiàn)ILE *fpo = fopen(BmpName,"rb");FILE *fpw = fopen(BmpNameLin,"wb+");fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo); fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo); fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);fread(m_pImage,m_nImage,1,fpo);//new和delete有效的進(jìn)行動態(tài)內(nèi)存的分配和釋放unsigned char *ImageSize; ImageSize = new unsigned char[m_nImage]; float red,green,blue;int X,Y; //一維坐標(biāo)轉(zhuǎn)換為二維坐標(biāo)int TR,TG,TB; //記錄紅綠藍(lán)坐標(biāo)位置//圖像增強(qiáng):平滑 for(int i=0; i<m_nImage ; i=i+3 ){//原圖:一維矩陣轉(zhuǎn)換為二維矩陣X=(i/3)%m_nWidth; //圖像在X列Y=(i/3)/m_nWidth; //圖像在Y行//賦值為黑色,相當(dāng)于清零red=green=blue=0;//對圖像進(jìn)行像素求和并取平均值 HWS維數(shù)for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ ) //第j行{for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ ) //第k列{if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight ) //防止越界{ //模板二 進(jìn)行模板平均,把該點(diǎn)像素分散到四周TR=j*m_nWidth*3+k*3; red+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);TG=j*m_nWidth*3+k*3+1;green+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);TB=j*m_nWidth*3+k*3+2;blue+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);}}}//對新圖像賦值ImageSize[i]=(unsigned char)(red);ImageSize[i+1]=(unsigned char)(green);ImageSize[i+2]=(unsigned char)(blue);}fwrite(ImageSize,m_nImage,1,fpw); fclose(fpo);fclose(fpw);numPicture = 2;level=400;Invalidate(); }? ? ? ? 運(yùn)行效果如下圖所示:
? ? ? ??4.中值濾波
? ? ? ? 中值濾波我的理解是:它不但可以去除孤點(diǎn)噪聲,而且可以保持圖像的邊緣特性,不會產(chǎn)生顯著的模糊;它的方法是把局部區(qū)域的像素按灰度等級進(jìn)行排序,再取該鄰域中灰度的中值作為當(dāng)前像素的灰度值。其步驟如下:
? ? ? ? (1).將濾波模板(含若干個點(diǎn)的滑動窗口)在圖像中漫游,并將模板中心與圖像中的某個像素位置重合;
? ? ? ? (2).讀取模板中各對應(yīng)像素的灰度值;
? ? ? ? (3).將這些灰度值從小到大排序;
? ? ? ? (4).取這一列數(shù)據(jù)的中間數(shù)據(jù),將其賦值給對應(yīng)模板中心位置的像素。
? ? ? ? 我采用的是3*3的模本,取矩陣中間位置像素替代原像素。代碼如下:
? ? ? ? 運(yùn)行效果如下圖所示:
? ? ? ? PS:這部分總算講述完成,算法都是根據(jù)自己的理解用底層代碼實(shí)現(xiàn)的,而不是向其它的通過調(diào)用GDI+庫實(shí)現(xiàn)??赡艽嬖谝?yàn)槔斫獠粔蚧蚱渌腻e誤,歡迎提出修改~
? ? ? ? 推薦資料:
? ? ? ??圖像平滑處理——OpenCV ? ? ? ? 數(shù)字圖像處理學(xué)習(xí)筆記——圖像平滑銳化?
? ? ? ? 中值濾波? ??
?
四. 圖像銳化
? ? ? ?有時還需要加強(qiáng)圖像中景物的邊緣和輪廓,邊緣和輪廓通常位于圖像中灰度突出的地方,因而可以直觀的想到用灰度的差分對邊緣和輪廓進(jìn)行提取,通常可以通過梯度算子進(jìn)行提取。圖像銳化的目的是提高圖像的對比度,從而使圖像更清晰,通過提高鄰域內(nèi)像素的灰度差來提高圖像的對比度。
? ? ? ?下面介紹圖像銳化的幾種算子及效果。
? ? ? ? 1.拉普拉斯算子(Laplacian)
? ? ? ? 拉普拉斯算子是圖像鄰域內(nèi)像素灰度差分計(jì)算的基礎(chǔ),通過二階微分推導(dǎo)出的一種圖像鄰域增強(qiáng)算法。它的基本思想是當(dāng)鄰域的中心像素灰度低于它所在鄰域內(nèi)的其他像素的平均灰度時,此中心像素的灰度應(yīng)該被進(jìn)一步降低;當(dāng)高于時進(jìn)一步提高中心像素的灰度,從而實(shí)現(xiàn)圖像銳化處理。
? ? ? ? 在算法實(shí)現(xiàn)過程中,通過對鄰域中心像素的四方向或八方向求梯度,并將梯度和相加來判斷中心像素灰度與鄰域內(nèi)其他像素灰度的關(guān)系,并用梯度運(yùn)算的結(jié)果對像素灰度進(jìn)行調(diào)整。
? ? ? ? 一個連續(xù)的二元函數(shù)f(x,y),其拉普拉斯運(yùn)算定義為:
? ? ? ? 對于數(shù)字圖像,拉普拉斯算子可以簡化為:
? ? ? ? 也可以表示為卷積的形式:
? ? ? ? 其中K=1,I=1時H(r,s)取下式,四方向模板:
? ? ? ? 通過模板可以發(fā)現(xiàn),當(dāng)鄰域內(nèi)像素灰度相同時,模板的卷積運(yùn)算結(jié)果為0;當(dāng)中心像素灰度高于鄰域內(nèi)其他像素的平均灰度時,模板的卷積運(yùn)算結(jié)果為正數(shù);當(dāng)中心像素的灰度低于鄰域內(nèi)其他像素的平均灰度時,模板的卷積為負(fù)數(shù)。對卷積運(yùn)算的結(jié)果用適當(dāng)?shù)乃ト跻蜃犹幚聿⒓釉谠行南袼厣?#xff0c;就可以實(shí)現(xiàn)圖像的銳化處理。
? ? ? ? 其中實(shí)現(xiàn)過程步驟如下:
? ? ? ? 添加子菜單和類向?qū)砑訉?shí)現(xiàn)函數(shù)
? ? ? ? 代碼如下:
/*****************************************/ /* 圖像銳化:我在menu中創(chuàng)建5個子的menu */ /* 防止出現(xiàn)平滑錯誤,一次只調(diào)用一個下拉單 */ /* ID_RH_Laplacian Laplacian拉普拉斯算子 */ /* ID_RH_Sobel Sobel算子 */ /* ID_RH_Prewitt Prewitt算子 */ /* ID_RH_Isotropic Isotropic算子 */ /* ID_RH_GTMB 高通模板H2 */ /*****************************************/void CImageProcessingView::OnRHLaplacian() {if(numPicture==0) {AfxMessageBox("載入圖片后才能圖像增強(qiáng)(銳化)!",MB_OK,0);return;}AfxMessageBox("圖像增強(qiáng)(銳化):采用拉普拉斯(Laplacian)算子!");//模板維數(shù):此四個模板均為3維的int HWS=3; int H[3][3]={{0,-1,0}, //模板為拉普拉斯算子(中心為4的Laplacian){-1,4,-1},{0,-1,0}};//讀寫文件FILE *fpo = fopen(BmpName,"rb");FILE *fpw = fopen(BmpNameLin,"wb+");fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);fread(m_pImage,m_nImage,1,fpo);//new和delete有效的進(jìn)行動態(tài)內(nèi)存的分配和釋放unsigned char *ImageSize; ImageSize=new unsigned char[m_nImage]; int red,green,blue;int X,Y; //一維坐標(biāo)轉(zhuǎn)換為二維坐標(biāo)int TR,TG,TB; //記錄紅綠藍(lán)坐標(biāo)位置//圖像增強(qiáng) 銳化for(int i=0; i<m_nImage ; i=i+3 ){X=(i/3)%m_nWidth; //X列Y=(i/3)/m_nWidth; //Y行red=green=blue=0;//對圖像進(jìn)行像素求和并取平均值 HWS維數(shù)for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ ) //第j行{for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ ) //第k列{if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight ){ TR=j*m_nWidth*3+k*3; red+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);TG=j*m_nWidth*3+k*3+1;green+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);TB=j*m_nWidth*3+k*3+2;blue+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);}}}//對新圖像賦值if(red>=0 && red<256) ImageSize[i]=red;else if(red<0) ImageSize[i]=0; //ImageSize[i]=-red;else ImageSize[i]=0;if(green>=0 && green<256) ImageSize[i+1]=green;else if(green<0) ImageSize[i+1]=0; //ImageSize[i+1]=-green;else ImageSize[i+1]=0;if(blue>=0 && blue<256) ImageSize[i+2]=blue;else if(blue<0) ImageSize[i+2]=0; //ImageSize[i+2]=-blue;else ImageSize[i+2]=0;}fwrite(ImageSize,m_nImage,1,fpw); fclose(fpo);fclose(fpw);numPicture = 2;level=400; Invalidate(); }? ? ? ? 運(yùn)行效果如下圖所示:
? ? ? ??2.高通濾波
? ? ? ? 常用的高通模板如下所示,其中H2有的書又稱為拉普拉斯八方向的銳化模板。
? ? ? ? 選取H2模板,代碼如下所示:
//高通模板 void CImageProcessingView::OnRhGtmb() {if(numPicture==0){AfxMessageBox("載入圖片后才能圖像增強(qiáng)(銳化)!",MB_OK,0);return;}AfxMessageBox("圖像增強(qiáng)(銳化):采用高通模板!");int HWS=3; int H[3][3]={{-1,-1,-1}, {-1,8,-1},{-1,-1,-1}};FILE *fpo = fopen(BmpName,"rb");FILE *fpw = fopen(BmpNameLin,"wb+");fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);fread(m_pImage,m_nImage,1,fpo);unsigned char *ImageSize; ImageSize=new unsigned char[m_nImage]; int red,green,blue;int X,Y; int TR,TG,TB; //圖像增強(qiáng) 銳化for(int i=0; i<m_nImage ; i=i+3 ){X=(i/3)%m_nWidth; //X列Y=(i/3)/m_nWidth; //Y行red=green=blue=0;//對圖像進(jìn)行像素求和并取平均值 HWS維數(shù)for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ ) //第j行{for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ ) //第k列{if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight ){ TR=j*m_nWidth*3+k*3; red+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);TG=j*m_nWidth*3+k*3+1;green+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);TB=j*m_nWidth*3+k*3+2;blue+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);}}}//對新圖像賦值if(red>=0 && red<256) ImageSize[i]=red;else if(red<0) ImageSize[i]=0; //ImageSize[i]=-red;else ImageSize[i]=0;if(green>=0 && green<256) ImageSize[i+1]=green;else if(green<0) ImageSize[i+1]=0; //ImageSize[i+1]=-green;else ImageSize[i+1]=0;if(blue>=0 && blue<256) ImageSize[i+2]=blue;else if(blue<0) ImageSize[i+2]=0; //ImageSize[i+2]=-blue;else ImageSize[i+2]=0;}fwrite(ImageSize,m_nImage,1,fpw); fclose(fpo);fclose(fpw);numPicture = 2;level=400; Invalidate(); }? ? ? ? 運(yùn)行效果如下圖所示,該效果相對較好:
?
? ? ? ?3.Sobel算子
? ? ? ? 代碼如下所示,需要注意X和Y兩個方向的模板處理:
//Sobel算子采用PPT上的d(x)d(y)模板 void CImageProcessingView::OnRHSobel() {if(numPicture==0){AfxMessageBox("載入圖片后才能圖像增強(qiáng)(銳化)!",MB_OK,0);return;}AfxMessageBox("圖像增強(qiáng)(銳化):采用Sobel算子!");int HWS=3; //模板為Sobel算子int HX[3][3]={{1,0,-1},{2,0,-2},{1,0,-1}};int HY[3][3]={{-1,-2,-1},{0,0,0},{1,2,1}};FILE *fpo = fopen(BmpName,"rb");FILE *fpw = fopen(BmpNameLin,"wb+");fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo); fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);fread(m_pImage,m_nImage,1,fpo);unsigned char *ImageSize; ImageSize=new unsigned char[m_nImage]; int redX,greenX,blueX;int redY,greenY,blueY;int X,Y; int TR,TG,TB; //圖像增強(qiáng) 銳化for(int i=0; i<m_nImage ; i=i+3 ){X=(i/3)%m_nWidth; //X列Y=(i/3)/m_nWidth; //Y行redX=greenX=blueX=0;redY=greenY=blueY=0;//對圖像進(jìn)行像素求和并取平均值 HWS維數(shù)for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ ) //第j行{for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ ) //第k列{if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight ){ TR=j*m_nWidth*3+k*3; redX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);redY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);TG=j*m_nWidth*3+k*3+1;greenX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);greenY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);TB=j*m_nWidth*3+k*3+2;blueX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);blueY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);}}}//s=(d(x)*d(x)+d(y)*d(y))開根號int R,G,B;R=(int)(sqrt(redX*redX*1.0+redY*redY*1.0));G=(int)(sqrt(greenX*greenX*1.0+greenY*greenY*1.0));B=(int)(sqrt(blueX*blueX*1.0+blueY*blueY*1.0));if(redX<0 && redY<0) ImageSize[i]=0;else if(R>255) ImageSize[i]=255;else ImageSize[i]=R;if(greenX<0 && greenY<0) ImageSize[i+1]=0;else if(G>255) ImageSize[i+1]=255;else ImageSize[i+1]=G;if(blueX<0 && blueY<0) ImageSize[i+2]=0;else if(B>255) ImageSize[i+2]=255;else ImageSize[i+2]=B;}fwrite(ImageSize,m_nImage,1,fpw); fclose(fpo);fclose(fpw);numPicture = 2;level=400; Invalidate(); }? ? ? ? 運(yùn)行效果如下圖所示:
? ? ? ? 如果采用Sobel邊緣細(xì)化,建議二值化(0和255閾值化)處理后再銳化,彩色圖建議先灰度處理再進(jìn)行其他處理。
? ? ??4.Isotropic算子
?
? ? ? ? 代碼實(shí)現(xiàn)如下:
//Isotropic算子采用PPT上的d(x)模板 d(y) void CImageProcessingView::OnRHIsotropic() {if(numPicture==0){AfxMessageBox("載入圖片后才能圖像增強(qiáng)(銳化)!",MB_OK,0);return;}AfxMessageBox("圖像增強(qiáng)(銳化):采用Isotropic算子!");int HWS=3; //模板為Isotropic算子float HX[3][3]={{1,0,-1},{sqrt(2.0),0,-sqrt(2.0)}, {1,0,-1} };float HY[3][3]={{-1,-sqrt(2.0),-1},{0,0,0}, {1,sqrt(2.0),1} };FILE *fpo = fopen(BmpName,"rb");FILE *fpw = fopen(BmpNameLin,"wb+");fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);fread(m_pImage,m_nImage,1,fpo);unsigned char *ImageSize; ImageSize=new unsigned char[m_nImage]; float redX,greenX,blueX;float redY,greenY,blueY;int X,Y; int TR,TG,TB; //圖像增強(qiáng)for(int i=0; i<m_nImage ; i=i+3 ){X=(i/3)%m_nWidth; //X列Y=(i/3)/m_nWidth; //Y行redX=greenX=blueX=0;redY=greenY=blueY=0;//對圖像進(jìn)行像素求和并取平均值 HWS維數(shù)for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ ) //第j行{for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ ) //第k列{if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight ){ TR=j*m_nWidth*3+k*3; redX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);redY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TR]);TG=j*m_nWidth*3+k*3+1;greenX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);greenY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TG]);TB=j*m_nWidth*3+k*3+2;blueX+=HX[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);blueY+=HY[(j-Y+HWS/2)][(k-X+HWS/2)]*(float)(m_pImage[TB]);}}}//對新圖像賦值 s=(d(x)*d(x)+d(y)*d(y))開根號int R,G,B;R=(int)(sqrt(redX*redX*1.0+redY*redY*1.0));G=(int)(sqrt(greenX*greenX*1.0+greenY*greenY*1.0));B=(int)(sqrt(blueX*blueX*1.0+blueY*blueY*1.0));if(redX<0 && redY<0) ImageSize[i]=0;else if(R>255) ImageSize[i]=255;else ImageSize[i]=R;if(greenX<0 && greenY<0) ImageSize[i+1]=0;else if(G>255) ImageSize[i+1]=255;else ImageSize[i+1]=G;if(blueX<0 && blueY<0) ImageSize[i+2]=0;else if(B>255) ImageSize[i+2]=255;else ImageSize[i+2]=B;}fwrite(ImageSize,m_nImage,1,fpw); fclose(fpo);fclose(fpw);numPicture = 2;level=400; Invalidate(); }? ? ? ? 運(yùn)行效果如下圖所示,效果與上面的Sobel類似:
? ? ? ?5.Prewitt算子
? ? ? ? 代碼如下圖所示:
//Prewitt算子采用PPT上的d(x)模板,不是d(y) void CImageProcessingView::OnRHPrewitt() {if(numPicture==0){AfxMessageBox("載入圖片后才能圖像增強(qiáng)(銳化)!",MB_OK,0);return;}AfxMessageBox("圖像增強(qiáng)(銳化):采用Prewitt算子!");int HWS=3; int H[3][3]={{1,0,-1}, //模板為Prewitt算子{1,0,-1},{1,0,-1}};FILE *fpo = fopen(BmpName,"rb");FILE *fpw = fopen(BmpNameLin,"wb+");fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);fread(m_pImage,m_nImage,1,fpo);unsigned char *ImageSize; ImageSize=new unsigned char[m_nImage]; int red,green,blue;int X,Y; int TR,TG,TB; //圖像增強(qiáng):平滑for(int i=0; i<m_nImage ; i=i+3 ){X=(i/3)%m_nWidth; //X列Y=(i/3)/m_nWidth; //Y行red=green=blue=0;//對圖像進(jìn)行像素求和并取平均值 HWS維數(shù)for(int j=Y-HWS/2 ; j<Y+HWS/2+1 ; j++ ) //第j行{for(int k=X-HWS/2 ; k<X+HWS/2+1 ; k++ ) //第k列{if( j>=0 && k>=0 && k<m_nWidth && j<m_nHeight ){ TR=j*m_nWidth*3+k*3; red+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TR]);TG=j*m_nWidth*3+k*3+1;green+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TG]);TB=j*m_nWidth*3+k*3+2;blue+=H[(j-Y+HWS/2)][(k-X+HWS/2)]*(m_pImage[TB]);}}}//對新圖像賦值if(red>=0 && red<256) ImageSize[i]=red;else if(red<0) ImageSize[i]=0; //ImageSize[i]=-red;else ImageSize[i]=0;if(green>=0 && green<256) ImageSize[i+1]=green;else if(green<0) ImageSize[i+1]=0; //ImageSize[i+1]=-green;else ImageSize[i+1]=0;if(blue>=0 && blue<256) ImageSize[i+2]=blue;else if(blue<0) ImageSize[i+2]=0; //ImageSize[i+2]=-blue;else ImageSize[i+2]=0; }fwrite(ImageSize,m_nImage,1,fpw); fclose(fpo);fclose(fpw);numPicture = 2;level=400; Invalidate(); }? ? ? ? 運(yùn)行效果如下圖所示,只選取了X分量:
? ? ? ? 最后還是希望文章對你有所幫助,如果文章有不足或錯誤之處,請海涵。自己給自己點(diǎn)個贊,挺不容易的,但還會繼續(xù)寫完~同時后面的圖像處理準(zhǔn)備研究些感興趣的東西,而不是這樣的長篇大論了,例如怎樣實(shí)現(xiàn)驗(yàn)證碼提取、如何實(shí)現(xiàn)圖像恢復(fù)、DICOM圖像等知識吧!
? ? ? (By:Eastmount 2015-06-08 下午6點(diǎn) ??http://blog.csdn.net/eastmount/)
總結(jié)
以上是生活随笔為你收集整理的【数字图像处理】七.MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【数字图像处理】五.MFC图像点运算之灰
- 下一篇: 搜索引擎和知识图谱那些事 (上).基础篇