基于BP神經(jīng)網(wǎng)絡(luò)的字符識別_第1頁
基于BP神經(jīng)網(wǎng)絡(luò)的字符識別_第2頁
基于BP神經(jīng)網(wǎng)絡(luò)的字符識別_第3頁
基于BP神經(jīng)網(wǎng)絡(luò)的字符識別_第4頁
基于BP神經(jīng)網(wǎng)絡(luò)的字符識別_第5頁
已閱讀5頁,還剩180頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

該系統(tǒng)是為了辨認(rèn)識別圖像中的數(shù)字而設(shè)計的,它通過對圖片的一系列處理,最后識別得出圖片中顯示的數(shù)字。系統(tǒng)既可以單獨使用,也可以把它作為一個識別系統(tǒng)的軟件核心應(yīng)用到車牌識別等系統(tǒng)中去。下面是系統(tǒng)具體要達(dá)到的基本技術(shù)要求(2)數(shù)字的識別準(zhǔn)確率大于90%;在本系統(tǒng)中用到了好多圖像處理中的相關(guān)技術(shù):比如灰度化、二值化、圖像內(nèi)容自動調(diào)對提取到的數(shù)字信息進(jìn)行分析判斷。因為系統(tǒng)運行的過程當(dāng)中,主要進(jìn)行的都是圖像處理,在這個過程當(dāng)中要進(jìn)行大量的數(shù)系統(tǒng)在實現(xiàn)的過程當(dāng)中,先分解成兩個大塊,就是圖像預(yù)處理模塊和數(shù)字識別模塊。其中圖像像預(yù)處理塊在對圖像進(jìn)行了一系列變換后把最后提取到的數(shù)字字符提交給數(shù)字識別模塊,然后進(jìn)行識別并給處結(jié)果。在這里用到了很多先進(jìn)的圖像預(yù)處理技術(shù)及神經(jīng)網(wǎng)絡(luò)技術(shù)。整個系統(tǒng)的程序?qū)崿F(xiàn)分為圖像預(yù)處理和神經(jīng)網(wǎng)絡(luò)識別兩大模塊。在圖像預(yù)處理的過程當(dāng)中,我們采用了許多圖像處理的技術(shù),最后把每個數(shù)字的特征提取出來。這些技術(shù)包括圖像數(shù)據(jù)讀取、圖像的灰度化、二值化、圖像的調(diào)整、離散噪聲點的去除、字符的切分、圖像的縮放、字符的細(xì)化、字符的平滑、圖像的求梯度等圖像處理技術(shù),最后是數(shù)字字符特征的提取。其結(jié)果再利用神經(jīng)網(wǎng)絡(luò)(這里我們選用BP網(wǎng)絡(luò))進(jìn)行字符識別。利用神經(jīng)網(wǎng)絡(luò)進(jìn)行字符識別的過程主要包括網(wǎng)絡(luò)的訓(xùn)練、數(shù)據(jù)的讀取、字符的判定、結(jié)果的輸出。下面按照程序執(zhí)行的順序介紹整個程序并逐一分析每一步的關(guān)鍵代碼。最后簡要講述一下程序的使用方法、注意事項以及本章小結(jié)。1.圖像數(shù)據(jù)的讀取、保存與屏幕顯示等基本函數(shù)要進(jìn)行圖像分析和處理首先就要得到圖像的數(shù)據(jù),這些數(shù)據(jù)包括圖像的寬、高、每個象BMP(bitmap的縮寫)文件格式是Windows本身可以直一個位圖文件頭,一個位圖信息頭,一個顏色表(又稱為色表)和位圖數(shù)據(jù)本身。位圖文件頭位圖文件頭包含關(guān)于這個文件的信息。如從哪里開始是位圖數(shù)據(jù)的定位信息、文件大小等等。以下是位圖文件頭結(jié)構(gòu)的定義:typedefstructtagBITMAPFILEHEADER{//bmfhWORDbfType;DWORDbfSize;WORDbfReserved1;WORDbfReserved2;bfOffBits;}BITMAPFILEHEADER;位圖信息頭位圖信息頭包含了單個像素所用字節(jié)數(shù)以及描述顏色的格式,此外還包括位圖的寬度、typedeftypedefstructtagBITMAPINFOHEADER{//bmihbiSize;LONGbiWidth;LONGbiHeight;WORDbiPlanes;WORDbiBitCountDWORDbiCompression;DWORDbiSizeImage;LONGbiXPelsPerMeter;LONGbiYPelsPerMeter;DWORDbiClrUsed;biClrImportant;}BITMAPINFOHEADER;結(jié)構(gòu)BITMAPINFOHEADER的字節(jié)以像素為單位的圖像寬度*以像素為單位的圖像長度*每個像素的位數(shù)圖像的壓縮格式(這個值幾乎總是為0)以字節(jié)為單位的圖像數(shù)據(jù)的大?。▽I_RGB壓縮方式而言)水平方向上的每米的像素個數(shù)垂直方向上的每米的像素個數(shù)調(diào)色板中實際使用的顏色數(shù)這個值通常為0,表示使用biBitCount確定的全部顏色,例外是使用的顏色的數(shù)目小于制定的顏色深度的顏色數(shù)目的最大值?,F(xiàn)實位圖時必須的顏色數(shù)這個值通常為0,表示所有的顏色都是必需的1,單色圖,調(diào)色板中含有兩種顏色,也就是我們通常說的黑白圖片加入了一個透明度,即RGBA模式。顏色表的圖像,由于其位圖像素數(shù)據(jù)中直接對對應(yīng)像素的RGB(A)顏色進(jìn)行描述,因而省卻了調(diào)色據(jù)這個索引到調(diào)色板去取得相應(yīng)的RGB(A)顏色。顏色表的作用就是創(chuàng)建調(diào)色板。對顯示卡值轉(zhuǎn)換到顯示卡的調(diào)色板來產(chǎn)生準(zhǔn)確的顏色。顏色表的顏色表項結(jié)構(gòu)的定義如下:typedefstructtagRGBQUAD{//rgbqBYTErgbBlue;BYTErgbGreen;BYTErgbRed;BYTErgbReserved;}RGBQUAD;位圖數(shù)據(jù)BMP文件的位圖數(shù)據(jù)格式依賴于編碼每個象素顏色所用的位數(shù)。對于一個256色的圖個象素的顏色索引。如果位圖數(shù)據(jù)中每行的字節(jié)數(shù)是奇數(shù),就要在每行都加一個附加的字節(jié)近年來,一種后綴名為jpg的位圖憑借較高的壓縮比和不俗的品質(zhì),而迅速成為圖像/圖形行業(yè)事實上的工業(yè)標(biāo)準(zhǔn)。本文沒有采用jpg位圖,但在這里也簡要的介jpg是24位的圖像文件格式,也是一種高效率的壓縮格式,文件由于其高效的壓縮效率和標(biāo)準(zhǔn)化要求,目前已廣泛用于彩色傳真、靜止圖像、電話會議、印刷及新聞圖片的傳送上。但那些被刪除的資料無法在解壓時還原,所以*.jpg文件并不適合看上去與照片沒有多大差別,非專業(yè)人士甚至無法分辨。同樣一幅畫面,用*.jpg格式儲存的高可達(dá)到24位,所以它被廣泛運用在Internet上,以節(jié)約寶貴的網(wǎng)絡(luò)傳輸資源。同樣,為了很多jpg圖像的編解碼的算法,限于篇幅,本文就不再贅述。如果要使用jpg格式的圖像,較常用到的圖像格式還有g(shù)if、tiff、png等等。由于本文的核心主要集中在圖像的預(yù)處理和BP神經(jīng)網(wǎng)絡(luò)識別部分,就不在圖像格式上耗費精力了。讀者需要進(jìn)一步了解圖像格式的可以詳細(xì)查閱相關(guān)資料。將其接口加以描述,以使讀者清晰每個函數(shù)的作用。同時作者自己對該庫又加以擴(kuò)充以滿足本程序的需要。文中沒有貼出而程序中又用到的代碼都在本書的附帶光盤中可以找到。首先來看7個圖像數(shù)據(jù)讀取/存儲/創(chuàng)建以及圖像基本信息獲取函數(shù)。返回值:說明:該函數(shù)將指定的文件中的DIB對象讀到指定的內(nèi)存區(qū)域中。除文件頭之外的內(nèi)容都將被讀入內(nèi)BOOLWINAPISaveDI參數(shù)參數(shù):返回值:說明:參數(shù):返回值:說明:參數(shù):返回值:說明:參數(shù):返回值:說明:參數(shù):返回值返回值:說明:以上6個函數(shù)是在圖像處理過程中讀取/保存圖像以及獲取圖像基本信息的6個最基本的可以十分便利的根據(jù)所提供的要創(chuàng)建的位圖的基本信息(高度、寬度、顏色位數(shù))來開辟內(nèi)存,并自動完成位圖信息頭的填充工作。/********************************************************************NewDIB()**參數(shù):*width-將要創(chuàng)建DIB的寬*height-將要創(chuàng)建DIB的高*biBitCount-將要創(chuàng)建DIB的位數(shù)。比如,如果要創(chuàng)建256色DIB,則此值為8**返回值:*HDIB-成功返回DIB的句柄,否則返回NULL。**說明:****************************************************************/HDIBWINAPINewDIB(longwidth,longheight,unsignedshortbiBitCount){longdwindth=(width*biBitCount/8+3)/4*4;WORDcolor__num;switch(biBitCount){case1:color__num=2;break;case4:color_num=16;break;case8:color__num=256;break;default:color_num=0;break;}//計算位圖數(shù)據(jù)所占的空間//dwindth*height為象素數(shù)據(jù)所占的空間dwBitsSize=dwindth*height+40+color__num*4;//建立指向位圖文件的指針LPSTRpDIB;//申請存儲空間,并建立指向位圖的句柄HDIBhDIB=(HDIB)::GlobalAlloc(GMEM__MOVEABLE|GMEM__ZEROINIT,dwBitsSize);//如果申請空間不成功返回錯誤信息if(hDIB==0){returnNULL;}pDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);//建立指向位圖信息頭結(jié)構(gòu)的指針LPBITMAPINFOlpmf=(LPBITMAPINFO)pDIB;//給位圖信息頭內(nèi)的各個參量賦值//指定位圖信息頭結(jié)構(gòu)的大小為40字節(jié)lpmf->bmiHeader.biSize=40;lpmf->bmiHeader.biWidth=width;lpmf->bmiHeader.biHeight=height;lpmf->bmiHeader.biPlanes=1;//確定新建位圖表示顏色是要用到的bit數(shù)lpmf->bmiHeader.biBitCount=biBitCount;lpmf->bmiHeader.biCompression=0;lpmf->bmiHeader.biSizeImage=dwindth*height;//指定目標(biāo)設(shè)備的水平分辨率lpmf->bmiHeader.biXPelsPerMeter=2925;//指定目標(biāo)設(shè)備的垂直分辨率lpmf->bmiHeader.biYPelsPerMeter=2925;biBitCount次lpmf->bmiHeader.biClrUsed=0;lpmf->bmiHeader.biClrImportant=0;if(color_num!=0){for(inti=0;i<color_num;i++){lpmf->bmiColors[i].rgbRed=(BYTE)i;lpmf->bmiColors[i].rgbGreen=(BYTE)i;lpmf->bmiColors[i].rgbBlue=(BYTE)i;}}::GlobalUnlock((HGLOBAL)hDIB);returnhDIB;}以上的7個函數(shù)是打開、保存、創(chuàng)建位圖以及獲取位圖基本信息的常用函數(shù),請讀者熟的講解。其他的3個作者自己編寫的函數(shù)將列出詳細(xì)的源代碼。參數(shù):返回值:說明:/***********************/***********************************************************************函數(shù)名稱:DisplayDIBCDC*pDC-指向當(dāng)前設(shè)備上下文(DiviceContext)的指針HDIBhDIB-要顯示的位圖的句柄**********************************************************************/voidDisplayDIB(CDC*pDC,HDIBhDIB){//鎖定位圖并獲取指向位圖的指針BYTE*lpDIB=(BYTE*)::GlobalLock(hDIB);//獲取DIB寬度和高度intcxDIB=::DIBWidth((char*)lpDIB);intcyDIB=::DIBHeight((char*)lpDIB);//設(shè)置位圖的尺寸CRectrcDIB,rcDest;rcDIB.top=rcDIB.left=0;rcDIB.right=cxDIB;rcDIB.bottom=cyDIB;rcDest=rcDIB;//清除屏幕ClearAll(pDC);//在客戶區(qū)顯示圖像::PaintDIB(pDC->m__hDC,rcDest,hDIB,rcDIB,NULL);//解除鎖定::GlobalUnlock((HGLOBAL)hDIB);}voidvoidClearAll(CDC*pDC){//設(shè)置清除區(qū)域CRectrect;rect.left=0;rect.top=0;rect.right=2000;rect.bottom=1000;//創(chuàng)建一白色畫筆CPenpen;pen.CreatePen(PS__SOLID,1,RGB(255,255,255));pDC->SelectObject(&pen);//繪制一白色矩形以清除客戶區(qū)pDC->Rectangle(&rect);//清除畫筆::DeleteObject(pen);}/**************************/***********************************************************************CDC*pDCHDIBhDIBCRectLinkcharRectunsignedintlinewidthCOLORREFcolor-指向當(dāng)前設(shè)備上下文的指針-指向位圖的句柄-一個元素為Crect類對象的鏈表-指出框的寬度-指出框的顏色之后會自動生成一個Crect鏈表。關(guān)于此鏈表的使用涉及到STL(StandardTemplateLibrary)技術(shù),***********************************************************************/voidDrawFrame(CDC*pDC,HDIBhDIB,CRectLinkcharRect,unsignedintlinewidth,COLORREFcolor){//創(chuàng)建畫筆CPenpen;pen.CreatePen(PS__SOLID,linewidth,color);pDC->SelectObject(&pen);//創(chuàng)建一個NULL畫刷::SelectObject(*pDC,GetStockObject(NULL__BRUSH));CRectrect,rect2;//鎖定位圖句柄并獲取其指針BYTE*lpDIB=(BYTE*)::GlobalLock((HGLOBAL)hDIB);while(!charRect.empty()){//從表頭上得到一個矩形rect2=rect=charRecrect2=rect=charRect.front();//從鏈表頭上面刪掉一個charRect.pop__front();//坐標(biāo)轉(zhuǎn)換//注意,這里原先的rect是相對于圖像原點(左下角)的,//而在屏幕上繪圖時,要轉(zhuǎn)換以客戶區(qū)為原點的坐標(biāo)rect.top=::DIBHeight((char*)lpDIB)-rect2.bottom;rect.bottom=::DIBHeight((char*)lpDIB)-rect2.top;pDC->Rectangle(&rect);}//解除鎖定::GlobalUnlock((HGLOBAL)hDIB);}至此,圖像讀取/保存/創(chuàng)建/顯示/清除屏幕/畫框等11個函數(shù)已介紹完畢。再提一下本程序自動刷新的實現(xiàn)。所謂自動刷新,即每當(dāng)屏幕內(nèi)容被遮擋或者說客戶區(qū)voidCChildView::OnPaint()voidCChildView::OnPaint(){CPaintDCdc(this);OnDraw(&dc);}//OnDraw函數(shù)voidCChildView::OnDraw(CDC*pDC){if(m__hDIB!=NULL)DisplayDIB(pDC,m__hDIB);}下面來進(jìn)入實質(zhì)的圖像預(yù)處理部分。2.圖像的預(yù)處理由于256色的位圖的調(diào)色板內(nèi)容比較復(fù)雜,使得圖像處理的許多算法都沒有辦法展開,因此有必要對它進(jìn)行灰度處理。所謂灰度圖像就是圖像的每一個象素的R、G、B分量的值是相等的。彩色圖像的每個象素的R、G、B值是不相同的,所以顯示出紅綠藍(lán)等各種顏色?;叶葓D像沒有這些顏色差異,有的只是亮度上的不同?;叶戎荡蟮南笏攸c比較亮(象素值最比較直接的一種就是給象素的rgb值各自一個加權(quán)系數(shù),然后求和;同時還要對調(diào)色板表項要注意的是,最后得到的結(jié)果一定要歸一到0-255之內(nèi)。因為這是每個字節(jié)表示圖像/*****************************************************************Convert256toGray()***無*****************************************************************/voidConvert256toGray(HDIBhDIB){LPSTRlpDIB;lpDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);LPSTRlpDIBBits;BYTE*lpSrc;LONGlWidth;LONGlHeight;LONGlLineBytes;//指向BITMAPINFO結(jié)構(gòu)的指針(Win3.0)LPBITMAPINFOlpbmi;////指向BITMAPCOREINFO結(jié)構(gòu)的指針LPBITMAPCOREINFOlpbmc;//獲取指向BITMAPINFO結(jié)構(gòu)的指針(Win3.0)lpbmi=(LPBITMAPINFO)lpDIB;//獲取指向BITMAPCOREINFO結(jié)構(gòu)的指針lpbmc=(LPBITMAPCOREINFO)lpDIB;//灰度映射表BYTEbMap[256];inti,j;for(i=0;i<256;i++){//計算該顏色對應(yīng)的灰度值bMap[i]=(BYTE)(0.299*lpbmi->bmiColors[i].rgbRed+0.587*lpbmi->bmiColors[i].rgbGreen+0.114*lpbmi->bmiColors[i].rgbBlue+0.5);lpbmi->bmiColors[i].rgbRed=i;lpbmi->bmiColors[i].rgbGreen=i;lpbmi->bmiColors[i].rgbBlue=i;//更新DIB調(diào)色板保留位lpbmi->bmiColors[i].rgbReserved=0;}lpDIBBits=::FindDIBBits(lpDIB);lWidth=::DIBWidth(lpDIB);lHeight=::DIBHeight(lpDIB);lLineBytes=WIDTHBYTES(lWidth*8);//逐行掃描for(ifor(i=0;i<lHeight;i++){for(j=0;j<lWidth;j++){lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*(lHeight-1-i)+j;//變換*lpSrc=bMap[*lpSrc];}}//解除鎖定::GlobalUnlock((HGLOBAL)hDIB);}下面我們來編寫由256色位圖轉(zhuǎn)化為灰度位圖的菜單處理事voidCChildView::OnIMGPRC256ToGray(){Convert256toGray(m_hDIB);DisplayDIB(pDC,m_hDIB);}在進(jìn)行了灰度化處理之后,圖像中的每個象素只有一個值,那就是象素的灰度值。它的大小決定了象素的亮暗程度。為了更加便利的開展下面的圖像處理操作,還需要對已經(jīng)得到的灰度圖像做一個二值化處理。圖像的二值化就是把圖像中的象素根據(jù)一定的標(biāo)準(zhǔn)分化成兩種顏色。在系統(tǒng)中是根據(jù)象素的灰度值處理成黑白兩種顏色。和灰度化相似的,圖像的二值化也有很多成熟的算法。它可以采用自適應(yīng)閥值法,也可以采用給定閥值法。系統(tǒng)中采用的是給定閥值的方法。因為考慮到所要進(jìn)行處理的圖像大多是從印刷出版物上掃描得來的底色大多為白色所以我們將這個閾值固定為220,讀者也可以根據(jù)實際的情況來自己進(jìn)行閾值的/********************************************************************函數(shù)名稱ConvertGrayToWhiteBlack()***返回值:無**功能:ConvertGrayToWhiteBlack*************************************************************************/voidConvertGrayToWhiteBlack(HDIBhDIB){LPSTRlpDIB;lpDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);LPSTRlpDIBBits;//指向DIB象素的指針BYTE*lpSrc;LONGlWidth;LONGlHeight;LONGlLineBytes;//找到DIB圖像象素起始位置lpDIBBits=::FindDIBBits(lpDIB);lWidth=::DIBWidth(lpDIB);lHeight=::DIBHeight(lpDIB);lLineBytes=WIDTHBYTES(lWidth*8);////更換每個象素的顏色索引(即按照灰度映射表換成灰度值)inti,j;for(i=0;i<lHeight;i++){for(j=0;j<lWidth;j++){lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*i+j;if(*lpSrc>220)*lpSrc=255;else*lpSrc=0;}}::GlobalUnlock((HGLOBAL)hDIB);}下面我們來編寫對灰度圖像進(jìn)行二值化處理的菜單處理時間的代碼:voidCChildView::OnIMGPRCGrayToWhiteBlack(){ConvertGrayToWhiteBlack(m__hDIB);//在屏幕上顯示位圖CDC*pDC=GetDC();DisplayDIB(pDC,m__hDIB);}((G[f(x,y)]由于需要處理的圖像大多有印刷出版物上掃描而來所以在很多的情況下字體模糊,對識別造成了一定的困難,所以有時我們要對圖像進(jìn)行銳化處理使模糊的圖像變得清晰起來,同通濾波法,我們在這里所采用的梯度銳化的方法就屬于微分法的一種。在這里我們采用定義如下:設(shè)原始圖像上的點為f(x,y)。定義f(x,y)在(x,y)處的梯度矢量為:G[f(i,j)]=|f(i,i)-f(i+1,j)|+|f(i,j)-f(i,j+1)|設(shè)一個判定閾值為Δ,變化后的圖像g(x,y)定義為:l(G[f(x,y)]>Δ)(G[f(x,y)]<Δ)通過公式可以看出梯度銳化可以讓模糊的邊緣變得清楚同時選擇合適的閾值還可以減弱和消除一些細(xì)小的噪聲。本程序中給出了梯度銳化的完整代碼,讀者也可以根據(jù)實際讀入圖片的質(zhì)量來選擇決定是否使用梯度銳化。事實證明,梯度銳化具備一定的去噪聲但同時會對字符的邊緣有所損傷。所以筆者建議在圖片中字符較為細(xì)小的時候不要使用梯度/***********************************************/*************************************************radientSharp()**HDIBhDIB-待處理圖像的句柄**無**功能:************************************************************************************************************/voidGradientSharp(HDIBhDIB){//指向DIB的指針LPSTRlpDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);//指向DIB象素指針LPSTRlpDIBBits;lpDIBBits=::FindDIBBits(lpDIB);//獲取圖像的寬度LONGlWidth=::DIBWidth((char*)lpDIB);//獲取圖像的長度LONGlHeight=::DIBHeight((char*)lpDIB);//閾值BYTEbThre=2;//調(diào)用GradSharp()函數(shù)進(jìn)行梯度板銳化unsignedchar*lpSrc;unsignedchar*lpSrc1;unsignedchar*lpSrc2;//循環(huán)變量LONGi;LONGj;LONGlLineBytes;BYTEbTemp;lLineBytes=WIDTHBYTES(lWidth*8);//每行for(i=0;i<lHeight;i++){//每列for(j=0;j<lWidth;j++){//指向DIB第i行,第j個象素的指針lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*(lHeight-1-i)i)+j;//指向DIB第i+1行,第j個象素的指針lpSrc1=(unsignedchar*)lpDIBBits+lLineBytes*(lHeight-2-i)+j;//指向DIB第i行,第j+1個象素的指針lpSrc2=(unsignedchar*)lpDIBBits+lLineBytes*(lHeight-1-i)+j+1;//計算梯度值abs((*lpSrc)-(*lpSrc1))+abs((*lpSrc)-(*lpSrc2));if(bTemp<255){if(bTemp>=bThre){//直接賦值為bTemplpSrc=bTemp;}}else{//直接賦值為255*lpSrc=255;}}}//最后還要處理一下圖像中最下面那行for(j=0;j<lWidth;j++){lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*0+j;//將此位置的象素設(shè)置為255,即白點*lpSrc=255;}//解除鎖定::GlobalUnlock((HGLOBAL)hDIB);}下面我們來編寫對圖像進(jìn)行梯度銳化菜單處理事件的響應(yīng)代碼:voidCChildView::OnImgprcSharp(){GradientSharp(m__hDIB);GradientSharp(m__hDIB);//在屏幕上顯示位圖CDC*pDC=GetDC();DisplayDIB(pDC,m__hDIB);}從處理的結(jié)果也可以看出圖像的邊緣變得清晰而且少了很多細(xì)小的雜點,但是梯度銳化所以務(wù)必提醒讀者注意,要根據(jù)實際情況酌情處理。圖像可能在掃描或者傳輸過程中夾帶了噪聲,去噪聲是圖像處理中常用的手法。通常去噪聲用濾波的方法,比如中值濾波、均值濾波。但是那樣的算法不適合用在處理字符這樣目標(biāo)狹長的圖像中,因為在濾波的過程中很有可能會去掉字符本身的象素。系統(tǒng)采用的是去除就考察和該黑色點間接或者直接相連接的黑色點的個數(shù)有多少,如果大于一定的值,那就說兩個函數(shù)。/*******************************************/**************************************************************RemoveScatterNoise()***返回值:*無******************************************************************/voidRemoveScatterNoise(HDIBhDIB){//指向DIB的指針LPSTRlpDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);//指向DIB象素指針LPSTRlpDIBBits;lpDIBBits=::FindDIBBits(lpDIB);//獲得圖像的長度LONGlWidth=::DIBWidth((char*)lpDIB);//獲得圖像的高度LONGlHeight=::DIBHeight((char*)lpDIB);intlength=15;//循環(huán)變量m__lianXuShu=0;i;j;k;LONGlLineBytes;lLineBytes=WIDTHBYTES(lWidth*8);LPSTRlpSrc;LPBYTELPBYTElplab=newBYTE[lHeight*lWidth];//開辟一塊用來保存離散判定結(jié)果的內(nèi)存數(shù)組bool*lpTemp=newbool[lHeight*lWidth];//初始化標(biāo)志數(shù)組for(i=0;i<lHeight*lWidth;i++){//將所有的標(biāo)志位設(shè)置為非lplab[i]=false;}//用來存放離散點的坐標(biāo)的數(shù)組CPointlab[21];//為循環(huán)變量賦初始值k=0;//掃描整個圖像//逐行掃描for(i=0;i<lHeight;i++){for(j=0;j<lWidth;j++){//先把標(biāo)志位置falsefor(k=0;k<m_lianXuShu;k++)lplab[lab[k].y*lWidth+lab[k].x]=false;m_lianXuShu=0;lpTemp[i*lWidth+j]DeleteScaterJudge(lpDIBBits,(WORD)lLineBytes,lplab,lWidth,lHeight,j,i,lab,length);}}for(i=0;i<lHeight;i++){for(j=0;j<lWidth;j++)for(j=0;j<lWidth;j++){if(lpTemp[i*lWidth+j]==false){//指向第i行第j個象素的指針lpSrc=(char*)lpDIBBits+lLineBytes*i+j;//將此象素設(shè)為白點*lpSrc=BYTE(255);}}}//解除鎖定::GlobalUnlock((HGLOBAL)hDIB);}/*****************************************************************/*******************************************************************DeleteScaterJudge()**LPSTRlpDIBBits-指向象素起始位置的指針*WORDlLineBytes-圖像每行的字節(jié)數(shù)*LPBYTElplab-標(biāo)志位數(shù)組*intlWidth-圖像的寬度*intlHeight-圖像的高度*CPointlab[]-存放議考察過的連續(xù)點坐標(biāo)*intlianXuShu-離散點的判定長度**Bool-是離散點返回false不是離散點返回true********************************************************************/boolDeleteScaterJudge(LPSTRlpDIBBits,WORDlLineBytes,LPBYTElplab,intlWidth,intlHeight,intx,inty,CPointlab[],intlianXuShu){//如果連續(xù)長度滿足要求,說明不是離散點,返回if(mlianXuShu>=lianXuShu)returnreturnTRUE;//長度加一m__lianXuShu++;//設(shè)定訪問標(biāo)志lplab[lWidth*y+x]=true;//保存訪問點坐標(biāo)lab[m__lianXuShu-1].x=x;lab[m__lianXuShu-1].y=y;//象素的灰度值intgray;//指向象素的指針LPSTRlpSrc;//長度判定//如果連續(xù)長度滿足要求,說明不是離散點,返回if(m__lianXuShu>=lianXuShu)returnTRUE;//下面進(jìn)入遞歸else{//考察上下左右以及左上、右上、左下、右下八個方向//如果是黑色點,則調(diào)用函數(shù)自身進(jìn)行遞歸//考察下面點lpSrc=(char*)lpDIBBits+lLineBytes*(y-1)+x;//傳遞灰度值gray=*lpSrc;//如果點在圖像內(nèi)、顏色為黑色并且沒有被訪問過if(y-1>=0&&gray==0&&lplab[(y-1)*lWidth+x]==false)//進(jìn)行遞歸處理DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x,y-1,lab,lianXuShu);//判斷長度//如果連續(xù)長度滿足要求,說明不是離散點,返回if(m__lianXuShu>=lianXuShu)returnTRUE;//左下點lpSrc=(char*)lpDIBBits+lpSrc=(char*)lpDIBBits+lLineBytes*(y-1)+x-1;//傳遞灰度值gray=*lpSrc;//如果點在圖像內(nèi)、顏色為黑色并且沒有被訪問過lplab[(y-1)*lWidth+x-1]==false)//進(jìn)行遞歸處理DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x-1,y-1,lab,lianXuShu);//判斷長度if(m__lianXuShu>=lianXuShu)returnTRUE;//左邊lpSrc=(char*)lpDIBBits+lLineBytes*y+x-1;//傳遞灰度值gray=*lpSrc;if(x-1>=0&&gray==0&&lplab[y*lWidth+x-1]==false)//進(jìn)行遞歸處理DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x-1,y,lab,lianXuShu);//判斷長度//如果連續(xù)長度滿足要求,說明不是離散點,返回if(m__lianXuShu>=lianXuShu)returnTRUE;//左上lpSrc=(char*)lpDIBBits+lLineBytes*(y+1)+x-1;//傳遞灰度值gray=*lpSrc;//如果點在圖像內(nèi)、顏色為黑色并且沒有被訪問過if(y+1<lHeight&&x-1>=0&&gray==0&&lplab[(y+1)*lWidth+x-1]==false)//進(jìn)行遞歸處理DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x-1,y+1,lab,lDeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x-1,y+1,lab,lianXuShu);//判斷長度//如果連續(xù)長度滿足要求,說明不是離散點,返回if(m__lianXuShu>=lianXuShu)returnTRUE;//上面lpSrc=(char*)lpDIBBits+lLineBytes*(y+1)+x;//傳遞灰度值gray=*lpSrc;//如果點在圖像內(nèi)、顏色為黑色并且沒有被訪問過if(y+1<lHeight&&gray==0&&lplab[(y+1)*lWidth+x]==false)//進(jìn)行遞歸處理DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x,y+1,lab,lianXuShu);//判斷長度//如果連續(xù)長度滿足要求,說明不是離散點,返回if(m__lianXuShu>=lianXuShu)returnTRUE;//右上lpSrc=(char*)lpDIBBits+lLineBytes*(y+1)+x+1;//傳遞灰度值gray=*lpSrc;//如果點在圖像內(nèi)、顏色為黑色并且沒有被訪問過if(y+1<lHeight&&x+1<lWidth&&gray==0&&lplab[(y+1)*lWidth+x+1]==false)//進(jìn)行遞歸處理DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x+1,y+1,lab,lianXuShu);//判斷長度//如果連續(xù)長度滿足要求,說明不是離散點,返回if(m__lianXuShu>=lianXuShu)returnTRUE;//右邊lpSrc=(char*)lpDIBBits+lLineBytes*y+x+1;//傳遞灰度值gray=*lpSrc;//如果點在圖像內(nèi)、顏色為黑色并且沒有被訪問過if(x+1<lWidth&&gray==0&&lplab[y*lWidth+x+1]==false)//進(jìn)行遞歸處理DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x+1,y,lab,lianXuShu);//判斷長度//如果連續(xù)長度滿足要求,說明不是離散點,返回if(m__lianXuShu>=lianXuShu)returnTRUE;//右下lpSrc=(char*)lpDIBBits+lLineBytes*(y-1)+x+1;//傳遞灰度值gray=*lpSrc;//如果點在圖像內(nèi)、顏色為黑色并且沒有被訪問過if(y-1>=0&&x+1<lWidth&&gray==0&&lplab[(y-1)*lWidth+x+1]==false)//進(jìn)行遞歸處理DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x+1,y-1,lab,lianXuShu);//判斷長度//如果連續(xù)長度滿足要求,說明不是離散點,返回if(m__lianXuShu>=lianXuShu)returnTRUE;}//如果遞歸結(jié)束,返回false,說明是離散點returnFALSE;}下面我們來編寫去除圖像中離散雜點噪聲的菜單處理事件的代碼://圖像預(yù)處理第4步:去離散雜點噪聲voidCChildView::OnImgprcRemoveNoise(){//調(diào)用去離散雜點噪聲的函數(shù)RemoveScatterNoise(m__hDIB);//在屏幕上顯示位圖CDC*pDC=GetDC();DisplayDIB(pDC,m__hDIB);}因為讀進(jìn)來的圖像可能存在傾斜,所以必須對它進(jìn)行調(diào)整,使得字符都處于同一水平位置,那樣即便利字符的分割也可以提高字符識別的準(zhǔn)確率。調(diào)整的算法主要是根據(jù)圖像上左右兩邊的黑色象素的平均高度來的。一般來象素的高度應(yīng)該是處于水平位置附近的,如果兩邊字符象素的平均位置有比較大的起落,那就說明圖像存在傾斜,需要進(jìn)行調(diào)整。具體來說,首先要分別計算圖像左半邊和右半邊的象的象素的映射。如果新圖像中的象素映射到舊圖像中時超出了舊圖像的范圍,則把新圖像中/*******************************************************/**********************************************************SlopeAdjust()***無*******************************************************************/voidSlopeAdjust(HDIBhDIB){LPSTRlpDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);LPSTRlpDIBBits;lpDIBBits=::FindDIBBits(lpDIB);unsignedchar*lpSrc;//循環(huán)變量LONGi;LONGj;LONGlLineBytes;//圖像的長度LONGlWidth;//圖像的寬度LONGlHeight;lWidth=::DIBWidth((char*)lpDIB);lHeight=::DIBHeight((char*)lpDIB);lLineBytes=WIDTHBYTES(lWidth*8);doubleleftaver=0.0,doublerightaver=0.0;doubleslope;LONGcounts=0;////掃描左半邊的圖像,求黑色象素的平均高度//行for(i=0;i<lHeight;i++){//列for(j=0;j<lWidth/2;j++){//指向第i行第j個象素的指針lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*i+j;//如果為黑點if(*lpSrc==0){//對其高度進(jìn)行統(tǒng)計疊加counts+=lWidth/2-j;leftaver+=i*(lWidth/2-j);}}}//計算平均高度leftaver/=counts;//將統(tǒng)計循環(huán)變量重新賦值counts=0;//掃描右半邊的圖像,求黑色象素的平均高度//行for(i=0;i<lHeight;i++){//列for(j=lWidth/2;j<lWidth;j++){//指向第i行第j個象素的指針lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*i+j;//如果為黑點if(*lpSrc==0){//進(jìn)行統(tǒng)計疊加counts+=lWidth-j;rightaver+=rightaver+=i*(lWidth-j);}}}//計算右半邊的平均高度rightaver/=counts;//計算斜率slope=(leftaver-rightaver)/(lWidth/2);//指向新的圖像象素起始位置的指針LPSTRlpNewDIBBits;//指向新圖像的指針LPSTRlpDst;//新圖像的句柄HLOCALnNewDIBBits=LocalAlloc(LHND,lLineBytes*lHeight);//鎖定內(nèi)存lpNewDIBBits=(char*)LocalLock(nNewDIBBits);//指向新圖像象素的指針lpDst=(char*)lpNewDIBBits;//為新圖像賦初始值memset(lpDst,(BYTE)255,lLineBytes*lHeight);//象素點的灰度值intgray;//位置映射值inti__src;//根據(jù)斜率,把當(dāng)前新圖像的點映射到源圖像的點//行for(i=0;i<lHeight;i++){//列for(j=0;j<lWidth;j++){//計算映射位置i__src=int(i-(j-lWidth/2)*slope);//如果點在圖像外,象素置白色if(i__src<0||i__src>=lHeight)gray=255;else{{//否則到源圖像中找點,取得象素值//指向第i__src行第j個象素的指針lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*i__src+j;gray=*lpSrc;}//把新圖像的點用得到的象素值填充//指向第i行第j個象素的指針lpDst=(char*)lpNewDIBBits+lLineBytes*i+j;*lpDst=gray;}}//將新的圖像的內(nèi)容拷貝到舊的圖像中memcpy(lpDIBBits,lpNewDIBBits,lLineBytes*lHeight);//解除鎖定::GlobalUnlock((HGLOBAL)hDIB);}下面我們來編寫傾斜度調(diào)整菜單處理事件的代碼:voidCChildView::OnImgprcAdjustSlope(){SlopeAdjust(m_hDIB);DisplayDIB(pDC,m_hDIB);}系統(tǒng)在讀進(jìn)來的圖像中一般會含有多個數(shù)字,識別的時候只能根據(jù)每個字符的特征來進(jìn)行判斷,所以還要進(jìn)行字符分割的工作。這一步工作就是把圖像中的字符獨立的分割出來。第一步,先自下向上對圖像進(jìn)行逐行掃描直至遇到第一個黑色的象素點。記錄下來。然后再由上向下對圖像進(jìn)行逐行掃描直至找到第一個黑色象素,這樣就找到圖像大致的高度范第二步,在這個高度范圍之內(nèi)在自左向右逐列進(jìn)行掃描,遇到第一個黑色象素時認(rèn)為是字符分割的起始位置,然后繼續(xù)掃描,直至遇到有一列中沒有黑色象素,則認(rèn)為這個字符分割結(jié)束,然后繼續(xù)掃描,按照上述的方法一直掃描直至圖像的最右端。這樣就得到了每個字第三步,在已知的每個字符比較精確的寬度范圍內(nèi),按照第一步的方法,分別進(jìn)行自上而下和自下而上的逐行掃描來獲取每個字符精確的高度范圍。/***************************************************CharSegment()**************************************************************/CRectLinkCharSegment(HANDLEhDIB){//清空用來保存每個字符區(qū)域的鏈表CRectLinkcharRect1,charRect2;charRect1.clear();charRect2.clear();//指向DIB的指針LPSTRlpDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);//指向DIB象素指針LPSTRlpDIBBits;lpDIBBits=::FindDIBBits(lpDIBBits=::FindDIBBits(lpDIB);//指向象素的的指針BYTE*lpSrc;//圖像的長度和寬度intheight,width;//獲取圖像的寬度width=(int)::DIBWidth(lpDIB);//獲取圖像的長度height=(int)::DIBHeight(lpDIB);//計算圖像每行的字節(jié)數(shù)LONGlLineBytes=WIDTHBYTES(width*8);//定義上下邊界兩個變量inttop,bottom;//象素的灰度值intgray;//設(shè)置循環(huán)變量inti,j;digicount=0;//從上往下掃描,找到上邊界//行for(i=0;i<height;i++){//列for(j=0;j<width;j++){//指向圖像第i行,第j個象素的指針lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*i+j;//獲得該點的灰度值gray=*(lpSrc);//看是否為黑點if(gray==0){top=i;i=height;i=height;//跳出循環(huán)break;}//如果該點不是黑點,繼續(xù)循環(huán)}}//從下往上掃描,找下邊界//行for(i=height-1;i>=0;i--){//列for(j=0;j<width;j++){//指向圖像第i行,第j個象素的指針lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*i+j;//獲取該點的灰度值gray=*(lpSrc);//判斷是否為黑點if(gray==0){//若為黑點,把此點作為字符大致的最低點bottom=i;//對i強(qiáng)行賦值以中斷循環(huán)i=-1;//跳出循環(huán)break;}//如果該點不是黑點,繼續(xù)循環(huán)}}//lab用作是否進(jìn)入一個字符分割的標(biāo)志boollab=false;//表明掃描一列中是否發(fā)現(xiàn)黑色點boolblack=false;////存放位置信息的結(jié)構(gòu)體CRectrect;//計數(shù)器置零digicount=0;//行for(i=0;i<width;i++){//開始掃描一列black=false;for(j=0;j<height;j++){//指向圖像第i行,第j個象素的指針lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*j+i;//獲取該點的灰度值gray=*(lpSrc);//判斷是否為黑點if(gray==0){//如果發(fā)現(xiàn)黑點,設(shè)置標(biāo)志位black=true;//如果還沒有進(jìn)入一個字符的分割if(lab==false){//設(shè)置左側(cè)邊界rect.left=i;//字符分割開始lab=true;}//如果字符分割已經(jīng)開始了else//跳出循環(huán)break;}}//如果已經(jīng)掃到了最右邊那列,說明整副圖像掃描完畢。退出if(i==(width-1))//退出整個循環(huán)break;//如果到此black仍為false,說明掃描了一列,都沒有發(fā)現(xiàn)黑點。表明當(dāng)前字符分割結(jié)束束if(lab==true&&black==false){rect.right=i;rect.top=top;rect.bottom=bottom;rect.InflateRect(1,1);charRect1.push_back(rect);lab=false;digicount++;}}charRect2=charRect1;charRect2.clear();CRectrectnew;while(!charRect1.empty()){rect=charRect1.front();charRect1.pop_front();////計算更加精確的矩形區(qū)域//獲得精確的左邊界rectnew.left=rect.left-1;//獲得精確的右邊界rectnew.right=rect.right+1;//通過獲得的精確左右邊界對上下邊境重新進(jìn)行精確定位//行for(i=rect.top;i<rect.bottom;i++){//列for(j=rect.left;j<rect.right;j++){lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*i+j;if(*lpSrc==0){//設(shè)置上邊界rectnew.top=i-1;//對i進(jìn)行強(qiáng)制定義以跳出循環(huán)i=rect.bottom;//跳出循環(huán)break;}}}//由下而上掃描計算下邊界//行for(i=rect.bottom-1;i>=rect.top;i--){//列for(j=rect.left;j<rect.right;j++){//指向圖像第i行,第j個象素的指針lpSrc=(unsignedchar*)lpDIBBits+lLineBytes*i+j;//該點如果為黑點if(*lpSrc==0){////設(shè)置下邊界rectnew.bottom=i+1;//對i進(jìn)行強(qiáng)制定義以跳出循環(huán)i=-1;//跳出循環(huán)break;}}}//將得到的新的準(zhǔn)確的位置信息從后面插到鏈表2的尾上charRect2.push__back(rectnew);}//將鏈表2傳遞給鏈表1charRect1=charRect2;//解除鎖定::GlobalUnlock(hDIB);//將鏈表1返回returncharRect1;}為了使讀者能夠清楚的看出圖像分割的結(jié)果作者在這里設(shè)計了一個函數(shù)DrawFrame用來在每個已經(jīng)分割完畢的字符周圍畫邊框,這個畫框函數(shù)只會起到標(biāo)識圖像的作用,并不會對位圖本身的內(nèi)容造成改變。#include#include<iostream>#include<deque>usingnamespacestd;typedefdeque<CRect>CRectLink;typedefdeque<HDIB>HDIBLink;表,不過其中的元素為位圖句柄HDIB。a.front()可以讀取鏈表頭部的一個矩形對象(只是讀取,不刪除)該鏈表的使用十分方便。下面我們來編寫字符分割菜單處理事件的代碼:voidCChildView::OnImgprcvoidCChildView::OnImgprcDivide(){//對位圖按照字符進(jìn)行分割,返回的是存有分割后的每個含字符區(qū)域的鏈表m__charRect=CharSegment(m__hDIB);//在屏幕上顯示位圖CDC*pDC=GetDC();DisplayDIB(pDC,m__hDIB);//在分割好的字符周圍畫框標(biāo)識DrawFrame(pDC,m__hDIB,m__charRect,2,RGB(20,60,200));}(7)圖像的歸一化處理因為掃描進(jìn)來的圖像中字符大小存在較大的差異,而相對來說,統(tǒng)一尺寸的字符識別的在系統(tǒng)實現(xiàn)中是統(tǒng)一到同一高度,然后根據(jù)高度來調(diào)整字符的寬度。具體算法如下:先得到原來字符的高度,跟系統(tǒng)要求的高度做比較,得出要變換的系數(shù),然后根據(jù)得到的系數(shù)求得變換后應(yīng)有得寬度。再得到寬度高度之后,把新圖像里面得點按照插值得方法映射到原圖像/***********************/********************************************************************StdDIBbyRect()**inttarWidth-標(biāo)準(zhǔn)化的寬度*inttarHeight-標(biāo)準(zhǔn)化的高度**無*********************************************************************/voidStdDIBbyRect(HDIBhDIB,inttarWidth,inttarHeight){BYTE*lpDIB=(BYTE*)::GlobalLock((HGLOBAL)hDIB);BYTE*lpDIBBits=(BYTE*)::FindDIBBits((char*)lpDIB);BYTE*lpSrc;LONGlWidth=::DIBWidth((char*)lpDIB);LONGlHeight=::DIBHeight((char*)lpDIB);inti;intj;LONGlLineBytes=WIDTHBYTES(lWidth*8);doublewscale,hscale;//開辟一塊臨時緩存區(qū),來存放變化后的圖像信息LPSTRlpNewDIBBits;LPSTRlpDst;HLOCALnNewDIBBits=LocalAlloc(LHND,lLineBytes*lHeight);lpNewDIBBits=(char*)LocalLock(nNewDIBBits);//指向緩存內(nèi)信息的指針lpDst=(char*)lpNewDIBBits;//將緩存區(qū)的內(nèi)容賦初始值memset(lpDst,(BYTE)255,lLineBytes*lHeight);//進(jìn)行映射操作的坐標(biāo)變量inti__src,j__src;////存放字符位置信息的Crect對象CRectrect;CRectrectnew;//先清空一個新的矩形區(qū)域鏈表以便存儲標(biāo)準(zhǔn)化后的矩形區(qū)域鏈表m__charRectCopy.clear();//從頭到尾逐個掃描各個結(jié)點while(!m__charRect.empty()){//從表頭上得到一個矩形rect=m_

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論