邊緣檢測和圖像分割的聯(lián)系:
邊緣檢測是通過圖像的梯度變化將圖像中梯度變化明顯的地方檢測出來,針對的是邊緣信息。圖像分割是將目標(biāo)分割出來,針對的是目標(biāo)對象,邊緣檢測是空間域圖像分割的一種方法,屬于包含關(guān)系
邊緣檢測后的圖像是二值圖像,對二值圖像可以運(yùn)用形態(tài)學(xué)操作來分割目標(biāo),所以邊緣檢測是圖像分割的一個前提。但分割不一定非要用邊緣檢測。
圖像分割:
概念:
圖像分割是將圖像劃分成若干個互不相交的小區(qū)域的過程,所謂小區(qū)域是某種意義下具有共同屬性的像素的連通集合。
從集合的觀點(diǎn)看:它應(yīng)該是具有如下性質(zhì)的一種點(diǎn)集,集合R代表整個區(qū)域,對R的分割可看作將R分成N個滿足以下五個條件的非空子集R1,R2,…,RN:
目的:
無論是圖像處理、分析、理解與識別,其基礎(chǔ)工作一般都建立在圖像分割的基礎(chǔ)上;
將圖像中有意義的特征或者應(yīng)用所需要的特征信息提取出來;
圖像分割的最終結(jié)果是將圖像分解成一些具有某種特征的單元,稱為圖像的基元;
相對于整幅圖像來說,這種圖像基元更容易被快速處理。
圖像分割原理
圖像分割的研究多年來一直受到人們的高度重視,至今提出了各種類型的分割算法。Pal把圖像分割算法分成了6類:閾值分割,像素分割、深度圖像分割、彩色圖像分割,邊緣檢測和基于模糊集的方法。但是,該方法中,各個類別的內(nèi)容是有重疊的。為了涵蓋不斷涌現(xiàn)的新方法,有的研究者將圖像分割算法分為以下六類:并行邊界分割技術(shù)、串行邊界分割技術(shù)、并行區(qū)域分割技術(shù)、串行區(qū)域分割技術(shù)、結(jié)合特定理論工具的分割技術(shù)和特殊圖像分割技術(shù)。
圖像分割的特征:
分割出來的各區(qū)域?qū)δ撤N性質(zhì)例如灰度,紋理而言具有相似性,區(qū)域內(nèi)部是連通的的且沒有過多小孔。
區(qū)域邊界是明確的
相鄰區(qū)域?qū)Ψ指钏罁?jù)的性質(zhì)有明顯的差異
圖像分割的方法:
一、基于像素灰度值的分割方法:閾值(門限)方法
二、基于區(qū)域的分割方法:通過直接確定區(qū)域間的邊界來實(shí)現(xiàn)分割的邊界方法;
三、基于邊緣的分割技術(shù):首先檢測邊緣像素, 再將邊緣像素連接起來構(gòu)成邊界形成分割。
圖像分割包含的內(nèi)容:
邊緣檢測
邊緣跟蹤 :
從圖像中一個邊緣點(diǎn)出發(fā),然后根據(jù)某種判別準(zhǔn)則搜索下一個邊緣點(diǎn)以此跟蹤出目標(biāo)邊界。
閾值分割 :
原始圖像——f(x,y)
灰度閾值——T
閾值運(yùn)算得二值圖像——g(x,y)
區(qū)域分割:
閾值分割法由于沒有或很少考慮空間關(guān)系,使多閾值選擇受到限制
于區(qū)域的分割方法可以彌補(bǔ)這點(diǎn)不足,它利用的是圖像的空間性質(zhì),該方法認(rèn)為分割出來的屬于同一區(qū)域的像素應(yīng)具有相似的性質(zhì),其概念是相當(dāng)直觀的。
傳統(tǒng)的區(qū)域分割算法有區(qū)域增長法和區(qū)域分裂合并法。該類方法在沒有先驗(yàn)知識可以利用時,對含有復(fù)雜場景或自然景物等先驗(yàn)知識不足的圖像進(jìn)行分割, 也可以取得較好的性能。但是,空間和時間開銷都比較大。
區(qū)域生長法主要考慮象素及其空間鄰域象素之間的關(guān)系
開始時確定一個或多個象素點(diǎn)作為種子,然后按某種相似性準(zhǔn)則增長區(qū)域,逐步生成具有某種均勻性的空間區(qū)域,將相鄰的具有相似性質(zhì)的象素或區(qū)域歸并從而逐步增長區(qū)域,直至沒有可以歸并的點(diǎn)或其它小區(qū)域?yàn)橹埂?/p>
區(qū)域內(nèi)象素的相似性度量可以包括平均灰度值、紋理、顏色等信息。
區(qū)域生長:
主要考慮像素及其空間鄰域像素之間的關(guān)系
開始時確定一個或多個像素點(diǎn)作為種子,然后按某種相似性準(zhǔn)則增長區(qū)域,逐步生成具有某種均勻性的空間區(qū)域,將相鄰的具有相似性質(zhì)的像素或區(qū)域歸并從而逐步增長區(qū)域,直至沒有可以歸并的點(diǎn)或其它小區(qū)域?yàn)橹埂?/p>
區(qū)域內(nèi)像素的相似性度量可以包括平均灰度值、紋理、顏色等信息。
主要步驟:
選擇合適的種子點(diǎn)
確定相似性準(zhǔn)則(生長準(zhǔn)則)
確定生長停止條件
區(qū)域分裂:
條件:如果區(qū)域的某些特性不滿足一致性準(zhǔn)則
開始:從圖像的最大區(qū)域開始,一般情況下,是從整幅圖像開始
注意:
確定分裂準(zhǔn)則(一致性準(zhǔn)則)
確定分裂方法,即如何分裂區(qū)域,使得分裂后的子區(qū)域的特性盡可能都滿足一致性準(zhǔn)則值
邊緣檢測:
在視覺計算理論框架中,抽取二維圖像上的邊緣、角點(diǎn)、紋理等基本特征,是整個系統(tǒng)框架中的第一步。這些特征所組成的圖稱為基元圖。
在不同“尺度”意義下的邊緣點(diǎn),在一定條件下包含了原圖像的全部信息。
定義:
?目前,具有對邊緣的描述性定義,即兩個具有不同灰度的均勻圖像區(qū)域的邊界,即邊界反映局部的灰度變化。
?局部邊緣是圖像中局部灰度級以簡單(即單調(diào))的方式作極快變換的小區(qū)域。這種局部變化可用一定窗口運(yùn)算的邊緣檢測算子來檢測。
邊緣的描述:
1) 邊緣法線方向——在某點(diǎn)灰度變化最劇烈的方向,與邊緣方向垂直;
2) 邊緣方向——與邊緣法線方向垂直,是目標(biāo)邊界的切線方向;
3) 邊緣強(qiáng)度——沿邊緣法線方向圖像局部的變化強(qiáng)度的量度。
邊緣檢測的基本思想是通過檢測每個像素和其鄰域的狀態(tài),以決定該像素是否位于一個物體的邊界上。如果一個像素位于一個物體的邊界上,則其鄰域像素的灰度值的變化就比較大。假如可以應(yīng)用某種算法檢測出這種變化并進(jìn)行量化表示,那么就可以確定物體的邊界。
邊緣檢測算法有如下四個步驟:
濾波:邊緣檢測算法主要是基于圖像強(qiáng)度的一階和二階導(dǎo)數(shù),但導(dǎo)數(shù)的計算對噪聲很敏感,因此必須使用濾波器來改善與噪聲有關(guān)的邊緣檢測器的性能.需要指出,大多數(shù)濾波器在降低噪聲的同時也導(dǎo)致了邊緣強(qiáng)度的損失,因此,增強(qiáng)邊緣和降低噪聲之間需要折衷.
增強(qiáng):增強(qiáng)邊緣的基礎(chǔ)是確定圖像各點(diǎn)鄰域強(qiáng)度的變化值.增強(qiáng)算法可以將鄰域(或局部)強(qiáng)度值有顯著變化的點(diǎn)突顯出來.邊緣增強(qiáng)一般是通過計算梯度幅值來完成的.
檢測:在圖像中有許多點(diǎn)的梯度幅值比較大,而這些點(diǎn)在特定的應(yīng)用領(lǐng)域中并不都是邊緣,所以應(yīng)該用某種方法來確定哪些點(diǎn)是邊緣點(diǎn).最簡單的邊緣檢測判據(jù)是梯度幅值閾值判據(jù).
定位:如果某一應(yīng)用場合要求確定邊緣位置,則邊緣的位置可在子像素分辨率上來估計,邊緣的方位也可以被估計出來.
在邊緣檢測算法中,前三個步驟用得十分普遍。這是因?yàn)榇蠖鄶?shù)場合下,僅僅需要邊緣檢測器指出邊緣出現(xiàn)在圖像某一像素點(diǎn)的附近,而沒有必要指出邊緣的精確位置或方向.邊緣檢測誤差通常是指邊緣誤分類誤差,即把假邊緣判別成邊緣而保留,而把真邊緣判別成假邊緣而去掉.邊緣估計誤差是用概率統(tǒng)計模型來描述邊緣的位置和方向誤差的.我們將邊緣檢測誤差和邊緣估計誤差區(qū)分開,是因?yàn)樗鼈兊挠嬎惴椒ㄍ耆煌湔`差模型也完全不同.
邊緣檢測的三個共性準(zhǔn)則:
?好的檢測結(jié)果,或者說對邊緣的誤測率盡可能低,就是在圖像邊緣出現(xiàn)的地方檢測結(jié)果中不應(yīng)該沒有;另一方面不要出現(xiàn)虛假的邊緣;
?對邊緣的定位要準(zhǔn)確,也就是我們標(biāo)記出的邊緣位置要和圖像上真正邊緣的中心位置充分接近;
?對同一邊緣要有盡可能低的響應(yīng)次數(shù),也就是檢測響應(yīng)最好是單像素的。
幾種常用的邊緣檢測算子主要有Roberts邊緣檢測算子,Sobel算子、Prewitt算子、Krisch邊緣算子,高斯-拉普拉斯算子。
圖像特征:
?圖像特征是指圖像中可用作標(biāo)志的屬性,它可以分為統(tǒng)計特征和視覺特征兩類。
?圖像的統(tǒng)計特征是指一些人為定義的特征,通過變換才能得到,如圖像的直方圖、矩、頻譜等;
?圖像的視覺特征是指人的視覺可直接感受到的自然特征,如區(qū)域的亮度、紋理或輪廓等
輪廓提取:
二值圖像輪廓提取的算法非常簡單, 就是掏空內(nèi)部點(diǎn): 如果原圖像中有一點(diǎn)為黑,且它的8個鄰點(diǎn)都是黑色時,說明該點(diǎn)是內(nèi)部點(diǎn), 將該點(diǎn)刪除(置為白色像素值255)。對圖像中所有像素點(diǎn)執(zhí)行該操作便可完成圖像輪廓的提取。
模板匹配:
模板匹配是指用一個較小的圖像,即模板與源圖像進(jìn)行比較, 以確定在源圖像中是否存在與該模板相同或相似的區(qū)域, 若該區(qū)域存在, 還可確定其位置并提取該區(qū)域。
形狀匹配:
形狀也是描述圖像內(nèi)容的一個重要特征, 利用形狀進(jìn)行匹配需要考慮三個問題。首先,形狀常與目標(biāo)聯(lián)系在一起,所以相對于顏色, 形狀特征可以看作是更高層次的圖像特征。要獲得有關(guān)目標(biāo)的形狀參數(shù),常常要先對圖像進(jìn)行分割, 所以形狀特征會受圖像分割效果的影響。其次,目標(biāo)形狀的描述是一個非常復(fù)雜的問題,至今還沒有找到能與人的感覺相一致的圖像形狀的確切數(shù)學(xué)定義。最后,從不同視角獲取的圖像中目標(biāo)形狀可能會有很大差別,為準(zhǔn)確進(jìn)行形狀匹配,需要解決平移、 尺度、 旋轉(zhuǎn)變換不變性的問題。
標(biāo)的形狀常常可以用目標(biāo)的輪廓來表示,而輪廓是由一系列邊界點(diǎn)所組成的。一般認(rèn)為,在較大尺度下常常能較可靠地消除誤檢并檢測到真正的邊界點(diǎn), 但在大尺度下對邊界的定位不易準(zhǔn)確。相反,在較小尺度下對真正邊界點(diǎn)的定位常比較準(zhǔn)確,但在小尺度下誤檢的比例會增加。所以,可考慮先在較大尺度下檢測出真正的邊界點(diǎn),再在較小尺度下對真正邊界點(diǎn)進(jìn)行較精確的定位。小波變換和分析作為一種多尺度、 多通道分析工具,比較適合對圖像進(jìn)行多尺度的邊界檢測。
圖像分割的實(shí)現(xiàn)
我用了Roberts算子、Sobel算子和Kirsh算子邊緣檢測的方法但都由于亮度不均等因素對圖像分割的效果不太好:
Sobel:
void sobel (unsignedchar* des, constunsignedchar* src, int width, int height)
{
for (int y=0; y《height; y++)
for (int x=0; x《width; x++)
des[y * width + x]=255;
/* Now compute the convolution, scaling */
for (int y=1; y《height-1; y++)
for (int x=1; x《width-1; x++)
{
double n = (src[(y+1)*width+x-1]+2*src[(y+1)*width+x]+src[(y+1)*width+x+1]) -
(src[(y-1)*width+x-1]+2*src[(y-1)*width+x]+src[(y-1)*width+x+1]);
double m = (src[(y-1)*width+x+1]+2*src[y*width+x+1]+src[(y+1)*width+x+1])-
(src[(y-1)*width+x-1]+2*src[y*width+x-1]+src[(y+1)*width+x-1]);
double k = (int)( sqrt( (double)(n*n + m*m) )/4.0 );
des[y * width + x] = k;
}
thresh (des, width,height);
}
Roberts算子:
void roberts(unsignedchar* des, constunsignedchar* src, int width, int height)
{
for (int y=0; y《height; y++)
for (int x=0; x《width; x++)
des[y * width + x]=255;
/* Now compute the convolution, scaling */
for (int y=1; y《height-1; y++)
for (int x=1; x《width-1; x++)
{
double n = src[y*width+x] - src[(y+1)*width+x+1];
double m = src[(y+1)*width+x] - src[y*width+x+1];
double k = abs(m)+abs(n);
des[y * width + x] = k;
}
thresh (des, width,height);
}
Kirsch算子:
void kirsch(unsigned char* des, const unsigned char* src, int width, int height)
{
// TODO: Add your command handler code here
//顯示數(shù)值
long int i,j,Ns;
static int nWeight[8][3][3];//對一個靜態(tài)整型數(shù)組賦初值,模板
double dGrad[8];
int nTmp[3][3],xx,yy;//每像素點(diǎn)的鄰域值
nWeight[0][0][0] = -1 ;
nWeight[0][0][1] = 0 ;
nWeight[0][0][2] = 1 ;
nWeight[0][1][0] = -2 ;
nWeight[0][1][1] = 0 ;
nWeight[0][1][2] = 2 ;
nWeight[0][2][0] = -1 ;
nWeight[0][2][1] = 0 ;
nWeight[0][2][2] = 1 ;
nWeight[1][0][0] = -1 ;
nWeight[1][0][1] = -2 ;
nWeight[1][0][2] = -1 ;
nWeight[1][1][0] = 0 ;
nWeight[1][1][1] = 0 ;
nWeight[1][1][2] = 0 ;
nWeight[1][2][0] = 1 ;
nWeight[1][2][1] = 2 ;
nWeight[1][2][2] = 1 ;//負(fù)號上下??? 已改成8個方向模板的值
nWeight[2][0][0] = 0 ;
nWeight[2][0][1] = -1 ;
nWeight[2][0][2] = -2 ;
nWeight[2][1][0] = 1 ;
nWeight[2][1][1] = 0 ;
nWeight[2][1][2] = -1 ;
nWeight[2][2][0] = 2 ;
nWeight[2][2][1] = 1 ;
nWeight[2][2][2] = 0 ;
nWeight[3][0][0] = 1 ;
nWeight[3][0][1] = 0 ;
nWeight[3][0][2] = -1 ;
nWeight[3][1][0] = 2 ;
nWeight[3][1][1] = 0 ;
nWeight[3][1][2] = -2 ;
nWeight[3][2][0] = 1 ;
nWeight[3][2][1] = 0 ;
nWeight[3][2][2] = -1 ;
nWeight[4][0][0] = 2 ;
nWeight[4][0][1] = 1 ;
nWeight[4][0][2] = 0 ;
nWeight[4][1][0] = 1 ;
nWeight[4][1][1] = 0 ;
nWeight[4][1][2] = -1 ;
nWeight[4][2][0] = 0 ;
nWeight[4][2][1] = -1 ;
nWeight[4][2][2] = -2 ;
nWeight[5][0][0] = 1 ;
nWeight[5][0][1] = 2 ;
nWeight[5][0][2] = 1 ;
nWeight[5][1][0] = 0 ;
nWeight[5][1][1] = 0 ;
nWeight[5][1][2] = 0 ;
nWeight[5][2][0] = -1 ;
nWeight[5][2][1] = -2 ;
nWeight[5][2][2] = -1 ;
nWeight[6][0][0] = 0 ;
nWeight[6][0][1] = 1 ;
nWeight[6][0][2] = 2 ;
nWeight[6][1][0] = -1 ;
nWeight[6][1][1] = 0 ;
nWeight[6][1][2] = 1 ;
nWeight[6][2][0] = -2 ;
nWeight[6][2][1] = -1 ;
nWeight[6][2][2] = 0 ;
nWeight[7][0][0] = -2 ;
nWeight[7][0][1] = -1 ;
nWeight[7][0][2] = 0 ;
nWeight[7][1][0] = -1 ;
nWeight[7][1][1] = 0 ;
nWeight[7][1][2] = 1 ;
nWeight[7][2][0] = 0 ;
nWeight[7][2][1] = -1 ;
nWeight[7][2][2] = 2 ;
//注意:每行的字節(jié)數(shù)必須是4的整數(shù)倍!!!先不考慮
Ns=height*width;
unsigned char* kk = new unsigned char[width * height]; //開始變換 initiion
for(i=0; i《height ; i++ )
//if(i==0)//tt change at 05.05.16
for(j=0 ; j《width ; j++ )
{
des[i*width + j]=0;//*(pdGrad+y*nWidth+x)
}
for(i=1; i《height-1 ; i++ )
{
for(j=1 ; j《width-1 ; j++ )
{
dGrad[0] = 0 ;
dGrad[1] = 0 ;
dGrad[2] = 0 ;
dGrad[3] = 0 ;
dGrad[4] = 0 ;
dGrad[5] = 0 ;
dGrad[6] = 0 ;
dGrad[7] = 0 ;
// sobel算子需要的各點(diǎn)象素值
// 模板第一行
nTmp[0][0] = src[(i-1)*width + j - 1 ];
nTmp[0][1] = src[(i-1)*width + j ] ;
nTmp[0][2] = src[(i-1)*width + j + 1 ] ;
// 模板第二行
nTmp[1][0] = src[i*width + j - 1 ] ;
nTmp[1][1] = src[i*width + j ] ;
nTmp[1][2] = src[i*width + j + 1 ] ;
// 模板第三行
nTmp[2][0] = src[(i+1)*width + j - 1 ] ;
nTmp[2][1] = src[(i+1)*width + j ] ;
nTmp[2][2] = src[(i+1)*width + j + 1 ] ;
// 計算梯度
for(yy=0; yy《3; yy++)
for(xx=0; xx《3; xx++)
{
dGrad[0] += nTmp[yy][xx] * nWeight[0][yy][xx] ;
dGrad[1] += nTmp[yy][xx] * nWeight[1][yy][xx] ;
dGrad[2] += nTmp[yy][xx] * nWeight[2][yy][xx] ;
dGrad[3] += nTmp[yy][xx] * nWeight[3][yy][xx] ;
dGrad[4] += nTmp[yy][xx] * nWeight[4][yy][xx] ;
dGrad[5] += nTmp[yy][xx] * nWeight[5][yy][xx] ;
dGrad[6] += nTmp[yy][xx] * nWeight[6][yy][xx] ;
dGrad[7] += nTmp[yy][xx] * nWeight[7][yy][xx] ;
}
for (xx=1;xx《8;xx++)
{
if (dGrad[xx]》dGrad[0])
dGrad[0]=dGrad[xx];
}
des[i*width + j]=dGrad[0];// 梯度值寫入src[i]
}
}
//設(shè)定閾值
int th[5120],newth[5120],shuN,newN,flagyuzhi;//winframe=32,ii,jj,initpos;
double thk,kmin,mvalue[8];
shuN=0;
thk=0.5;
for (i=0;i《Ns;i++)//每層的每個點(diǎn)
{
if ((i》=width) && (i《(Ns-width)))//若是非邊界點(diǎn),則……
{
if ((i%width!=0) && ((i+1)%width!=0))
{
//每點(diǎn)做變換,首先求kirs(c)h算子
mvalue[0]=fabs(double(des[i+1]+des[i+width+1]+des[i+width]+
des[i+width-1]+des[i-1]-des[i-width-1]-
des[i-width]-des[i-width+1]));
mvalue[1]=fabs(double(des[i+width+1]+des[i+width]+
des[i+width-1]+des[i-1]+des[i-width-1]-
des[i-width]-des[i-width+1]-des[i+1]));
mvalue[2]=fabs(double(des[i+width]+des[i+width-1]+des[i-1]+
des[i-width-1]+des[i-width]-
des[i-width+1]-des[i+1]-des[i+width+1]));
mvalue[3]=fabs(double(des[i+width-1]+des[i-1]+
des[i-width-1]+des[i-width]+
des[i-width+1]-des[i+1]-des[i+width+1]-
des[i+width]));
mvalue[4]=fabs(double(des[i-1]+des[i-width-1]+
des[i-width]+des[i-width+1]+des[i+1]-
des[i+width+1]-des[i+width]-
des[i+width-1]));
mvalue[5]=fabs(double(des[i-width-1]+des[i-width]+
des[i-width+1]+des[i+1]+des[i+width+1]-
des[i+width]-des[i+width-1]-des[i-1]));
mvalue[6]=fabs(double(des[i-width]+des[i-width+1]+des[i+1]+
des[i+width+1]+des[i+width]-
des[i+width-1]-des[i-1]-des[i-width-1]));
mvalue[7]=fabs(double(des[i-width+1]+des[i+1]+des[i+width+1]+
des[i+width]+des[i+width-1]-
des[i-1]-des[i-width-1]-des[i-width]));
for (j=1;j《8;j++) //比較得出算子,mvalue[0]為最大
{
if (mvalue[0]《mvalue[j])
mvalue[0]=mvalue[j];
}
kk[i]=max(1,mvalue[0]/15);
if (shuN==0)
kmin=kk[i];
if (kk[i]》thk)
{
th[shuN]=i;
kmin=min(kmin,kk[i]);
shuN++;
if (shuN》=5*height)//若大于5*H個點(diǎn),則重新確定
{
//AfxMessageBox(“l(fā)ll”);
thk=kmin;
newN=0;
for (j=0;j《shuN;j++)
{
if (kk[th[j]]》thk)
{
if (newN==0)
kmin=kk[th[j]];
newth[newN]=th[j];
kmin=min(kmin,kk[th[j]]);
newN++;
}
//else des[th[j]]=0;
}
for (j=0;j《5120;j++)
{
th[j]=newth[j];
}
shuN=newN;
}//重新確定完
}
//非邊界的每點(diǎn)變換結(jié)束
}
}
}//一層結(jié)束
for (i=0;i《Ns;i++)//每層的每個點(diǎn)
{
if (des[i]《thk)
des[i]=0;
}
thresh (des, width,height);
//菜單函數(shù)結(jié)束
}
下面三圖分別為sobel、Roberts、kerish邊緣檢測的結(jié)果:
之后打算用霍夫變換檢測直線找矩形框,但是由于光照形成的噪點(diǎn)效果并不是很好,因此最后用自適應(yīng)直方圖均衡去除光照影響加自適應(yīng)中值濾波再用投影法實(shí)現(xiàn)矩形框和數(shù)字的檢測。具體如下:
int main()
{
IplImage* src = cvLoadImage(“dm5.bmp”);
IplImage* gray = cvCreateImage(cvGetSize(src), src-》depth, 1);
cvCvtColor(src,gray,CV_BGR2GRAY); //灰度化
int width = src-》width;
int height = src-》height;
IplImage* dst = cvCreateImage(cvGetSize(src), src-》depth, gray-》nChannels);
IplImage* scr = cvCreateImage(cvGetSize(gray), gray-》depth, gray-》nChannels);
cvSmooth(gray, gray, CV_MEDIAN, 3, 0, 0, 0); //中值濾波,消除小的噪聲;
cvSmooth(gray, gray, CV_GAUSSIAN, 9, gray-》nChannels);//高斯濾波
cvCvtColor(src,scr,CV_BGR2GRAY);
cvThreshold( gray, gray, 190, 255, CV_THRESH_BINARY);//二值化
int nChannels =gray-》nChannels;
cvNamedWindow(“origin”,0);
cvResizeWindow(“origin”,int(width/2),int(height/2));
cvShowImage(“origin”, src);
unsigned char* img = new unsigned char[width * height ];
unsigned char* des = new unsigned char[width * height ];
unsigned char* gra = new unsigned char[width * height];
unsigned char* grt = new unsigned char[width * height];
img_data(gray, gra,width,height, nChannels);
img_data(scr, img,width,height,nChannels);
AHE(des, img, width, height,nChannels,10);//自適應(yīng)直方圖均衡
Projection( grt,gra,width,height); //投影檢測表盤區(qū)域
img_extract(des,grt,width,height,1); //表盤區(qū)域還原
//kirsch(des,gra, width,height);
data_img( scr, des, width, height, nChannels);
cvNamedWindow(“表盤”,0);
cvResizeWindow(“表盤”,int(width/2),int(height/2));
cvShowImage(“表盤”, scr);
cvThreshold(scr, scr, 100, 255, CV_THRESH_BINARY); //表盤區(qū)域二值化以查找數(shù)字
img_data(scr, img,width,height,nChannels);
Adaptivemedianfilter(des, img, width, height, nChannels); //自適應(yīng)中值濾波去噪
ImageDilation( img, des, width, height,nChannels,1);
ImageErosion( des,img,width, height,nChannels,1); //經(jīng)過一次膨脹腐蝕去噪
location(img, des, width, height); //找出數(shù)字所在區(qū)域
data_img( scr, img, width, height, nChannels);
cvNamedWindow(“數(shù)字”,0);
cvResizeWindow(“數(shù)字”,int(width/2),int(height/2));
cvSaveImage(“123.bmp”,scr);
cvShowImage(“數(shù)字”, scr);
data_img( gray,des, width, height, nChannels);
cvNamedWindow(“erzhi”,0);
cvResizeWindow(“erzhi”,int(width/2),int(height/2));
cvShowImage(“erzhi”, gray);
cvWaitKey(0);
}
/**************************************************************************
函數(shù)名:Projection
功 能:投影法找出矩形區(qū)域
輸 入:目標(biāo)圖像des, 原圖像 src,圖像寬width, 高h(yuǎn)eight
返回值:no
*************************************************************************/
void Projection(unsigned char* des, const unsigned char* src,int width, int height)
{
int* h_sum = new int[height];
int* w_sum = new int[width];
int up=0;
int below=height;
int left=0;
int right=width;
for(int y=0;y《height;y++)
{
for(int x=0;x《width;x++)
{
des[y*width+x]=255;
}
}
for(int y=0;y《height;y++)
{
h_sum[y]=0;
for(int x=0;x《width;x++)
{
//printf(“src %d”,src[y*width+x]);
h_sum[y]=h_sum[y]+src[y*width+x];
}
//printf(“%d行%d ”,y,h_sum[y]);
}
for(int y=height/2;y《height;y++)
{
if((h_sum[y]-h_sum[height/2])》255*60)
{
below=y;
break;
}
}
for(int y=height/2;y》0;y--)
{
if((h_sum[y]-h_sum[height/2])》255*60)
{
up=y;
break;
}
}
for(int x=0;x《width;x++)
{
w_sum[x]=0;
for(int y=up;y《below;y++)
{
w_sum[x]=w_sum[x]+src[y*width+x];
}
//printf(“%d列%d ”,x,w_sum[x]);
}
int max_r=0;
int max_l=0;
for(int x=width/2+100;x《width;x++)
{
if(w_sum[x]》max_r)
{
right=x;
max_r=w_sum[x];
}
}
for(int x=width/2-100;x》0;x--)
{
if(w_sum[x]》max_l)
{
left=x;
max_l=w_sum[x];
}
}
for(int y=up;y《below;y++)
{
for(int x=left;x《right;x++)
{
des[y*width+x]=0;
}
}
printf(“up%d below%d left%d right%d”,up, below,left, right);
}
void img_extract(unsigned char* des, const unsigned char* src,int width, int height, int nChannels)
{
for (int y=0;y《height;y++)
for(int x=0;x《width;x++)
if(src[y*width+x]!=0)
{
for(int n = 0; n 《 nChannels; n++)
{
des[y * width * nChannels + x * nChannels + n ] = 255;
}
}
}
/************************************************************************
函數(shù)名:location
功 能:投影法找出數(shù)字
輸 入:目標(biāo)圖像des, 原圖像 src,圖像寬width, 高h(yuǎn)eight
返回值:no
**********************************************************************/
void location(unsigned char* des, const unsigned char* src,int width, int height)
{
int* h_sum = new int[height];
int* w_sum = new int[width];
int up=0;
int below=height;
int left=0;
int right=width;
for(int y=0;y《height;y++)
{
for(int x=0;x《width;x++)
{
des[y*width+x]=255;
}
}
for(int y=0;y《height;y++)
{
h_sum[y]=0;
for(int x=0;x《width;x++)
{
//printf(“src %d”,src[y*width+x]);
h_sum[y]=h_sum[y]+src[y*width+x];
}
//printf(“%d行%d ”,y,h_sum[y]);
}
int h_mid=(h_sum[height/2]+h_sum[height/2-10]+h_sum[height/2-20]+h_sum[height/2-30]+h_sum[height/2-40]);
h_mid=h_mid/5;
for(int y=height/2;y《height;y++)
{
if((h_sum[y]-h_mid)》255*35)
{
below=y;
break;
}
}
for(int y=height/2;y》0;y--)
{
if((h_sum[y]-h_mid)》255*37)
{
up=y;
break;
}
}
for(int x=0;x《width;x++)
{
w_sum[x]=0;
for(int y=up;y《below;y++)
{
w_sum[x]=w_sum[x]+src[y*width+x];
}
//printf(“%d列%d ”,x,w_sum[x]);
}
int right_start=width-10;
for(int x=width-10;x》width/2;x--)
{
if(w_sum[x]!=(below-up)*255)
{
right_start=x;
break;
}
}
for(int x=right_start-45;x》width/2;x--)
{
if(w_sum[x]《255*(below-up-40))
{
right=x;
break;
}
}
int left_start=10;
for(int x=10;x《width;x++)
{
if(w_sum[x]!=(below-up)*255)
{
left_start=x;
break;
}
}
for(int x=left_start+100;x《width;x++)
{
if(w_sum[x]《255*(below-up-20))
{
left=x;
break;
}
}
for(int y=up;y《below;y++)
{
for(int x=left-5;x《right+5;x++)
{
des[y*width+x]=src[y*width+x];
}
}
printf(“up%d below%d left%d right%d left_start%d h_mid%d height/2%d width%d”,up, below,left, right,left_start,h_mid,height/2,width);
}
結(jié)果展示
評論