<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          OpenCV實(shí)現(xiàn)基于邊緣的模板匹配--適用部分遮擋和光照變化情形(附源碼)

          共 12029字,需瀏覽 25分鐘

           ·

          2023-07-28 07:10

             
          點(diǎn)擊上方小白學(xué)視覺(jué)”,選擇加"星標(biāo)"或“置頂
              
          重磅干貨,第一時(shí)間送達(dá)

          介紹

          模板匹配是一個(gè)圖像處理問(wèn)題,當(dāng)其姿態(tài)(X,Y,θ)未知時(shí),使用另一張搜索圖像中的模板圖像找到對(duì)象的位置。在本文中,我們實(shí)現(xiàn)了一種算法,該算法使用對(duì)象的邊緣信息來(lái)識(shí)別搜索圖像中的對(duì)象。

          背景

          由于其速度和可靠性問(wèn)題,模板匹配本質(zhì)上是一個(gè)棘手的問(wèn)題。當(dāng)對(duì)象部分可見(jiàn)或與其他對(duì)象混合時(shí),該解決方案應(yīng)對(duì)亮度變化具有魯棒性,最重要的是,該算法應(yīng)具有計(jì)算效率。解決這個(gè)問(wèn)題主要有兩種方法,基于灰度值的匹配(或基于區(qū)域的匹配)和基于特征的匹配(非基于區(qū)域的匹配)。

          基于灰度值的方法:在基于灰度值的匹配中,歸一化互相關(guān) (NCC) 算法早在過(guò)去就已為人所知。這通常在每一步通過(guò)減去平均值并除以標(biāo)準(zhǔn)偏差來(lái)完成。模板 t(x, y) 與子圖像 f(x, y) 的互相關(guān)為:

          其中 n 是 t(x, y) 和 f(x, y) 中的像素?cái)?shù)。[維基]

          盡管該方法對(duì)線性光照變化具有魯棒性,但當(dāng)對(duì)象部分可見(jiàn)或?qū)ο笈c其他對(duì)象混合時(shí),該算法將失敗。此外,該算法的計(jì)算成本很高,因?yàn)樗枰?jì)算模板圖像中所有像素與搜索圖像之間的相關(guān)性。

          基于特征的方法:在圖像處理領(lǐng)域中使用了幾種基于特征的模板匹配方法。與基于邊緣的物體識(shí)別一樣,物體邊緣是用于匹配的特征,在廣義霍夫變換中,物體的幾何特征將用于匹配。

          在本文中,我們實(shí)現(xiàn)了一種算法,該算法使用對(duì)象的邊緣信息來(lái)識(shí)別搜索圖像中的對(duì)象。此實(shí)現(xiàn)使用開(kāi)源計(jì)算機(jī)視覺(jué)庫(kù)作為平臺(tái)。

          編譯示例代碼

          我們使用 OpenCV 2.0 和 Visual Studio 2008 來(lái)開(kāi)發(fā)此代碼。要編譯示例代碼,我們需要安裝 OpenCV。

          OpenCV 可以從這里免費(fèi)下載OpenCV的開(kāi)放源碼?動(dòng)態(tài)數(shù)值V ision)是一種用于實(shí)時(shí)計(jì)算機(jī)視覺(jué)編程功能的庫(kù)。下載 OpenCV 并將其安裝在您的系統(tǒng)中。安裝信息可以從這里閱讀

          我們需要配置我們的 Visual Studio 環(huán)境。可以從此處閱讀此信息

          算法

          在這里,我們將解釋基于邊緣的模板匹配技術(shù)。邊緣可以定義為數(shù)字圖像中圖像亮度急劇變化或具有不連續(xù)性的點(diǎn)。從技術(shù)上講,它是一種離散微分運(yùn)算,計(jì)算圖像強(qiáng)度函數(shù)的梯度近似值。

          邊緣檢測(cè)的方法有很多,但大多數(shù)可以分為兩類(lèi):基于搜索的和基于過(guò)零的。基于搜索的方法通過(guò)首先計(jì)算邊緣強(qiáng)度的度量來(lái)檢測(cè)邊緣,通常是一階導(dǎo)數(shù)表達(dá)式,例如梯度幅度,然后使用計(jì)算的局部方向的估計(jì)來(lái)搜索梯度幅度的局部方向最大值邊緣,通常是梯度方向。在這里,我們使用了一種由 Sobel 實(shí)現(xiàn)的方法,稱為 Sobel 算子。操作員計(jì)算每個(gè)點(diǎn)的圖像強(qiáng)度梯度,給出從明到暗的最大可能增加方向以及該方向的變化率。

          我們?cè)?X 方向和 Y 方向使用這些梯度或?qū)?shù)進(jìn)行匹配。

          該算法包括兩個(gè)步驟。首先,我們需要為模板圖像創(chuàng)建一個(gè)基于邊緣的模型,然后我們使用這個(gè)模型在搜索圖像中進(jìn)行搜索。

          創(chuàng)建基于邊緣的模板模型

          我們首先從模板圖像的邊緣創(chuàng)建一個(gè)數(shù)據(jù)集或模板模型,用于在搜索圖像中查找該對(duì)象的姿態(tài)。

          在這里,我們使用 Canny 邊緣檢測(cè)方法的變體來(lái)查找邊緣。您可以在此處閱讀有關(guān) Canny 邊緣檢測(cè)的更多信息對(duì)于邊緣提取,Canny 使用以下步驟:

          第一步:求圖像的強(qiáng)度梯度

          在模板圖像上使用 Sobel 過(guò)濾器,它返回 X (Gx) 和 Y (Gy) 方向的梯度。根據(jù)這個(gè)梯度,我們將使用以下公式計(jì)算邊緣大小和方向:

          我們正在使用 OpenCV 函數(shù)來(lái)查找這些值。

          cvSobel( src, gx, 1,0, 3 ); //gradient in X directioncvSobel( src, gy, 0, 1, 3 ); //gradient in Y direction
          for( i = 1; i < Ssize.height-1; i++ ){ for( j = 1; j < Ssize.width-1; j++ ) { _sdx = (short*)(gx->data.ptr + gx->step*i); _sdy = (short*)(gy->data.ptr + gy->step*i); fdx = _sdx[j]; fdy = _sdy[j]; // read x, y derivatives
          //Magnitude = Sqrt(gx^2 +gy^2) MagG = sqrt((float)(fdx*fdx) + (float)(fdy*fdy)); //Direction = invtan (Gy / Gx) direction =cvFastArctan((float)fdy,(float)fdx); magMat[i][j] = MagG; if(MagG>MaxGradient) MaxGradient=MagG; // get maximum gradient value for normalizing.
          // get closest angle from 0, 45, 90, 135 set if ( (direction>0 && direction < 22.5) || (direction >157.5 && direction < 202.5) || (direction>337.5 && direction<360) ) direction = 0; else if ( (direction>22.5 && direction < 67.5) || (direction >202.5 && direction <247.5) ) direction = 45; else if ( (direction >67.5 && direction < 112.5)|| (direction>247.5 && direction<292.5) ) direction = 90; else if ( (direction >112.5 && direction < 157.5)|| (direction>292.5 && direction<337.5) ) direction = 135; else direction = 0; orients[count] = (int)direction; count++; }}

          一旦找到邊緣方向,下一步就是關(guān)聯(lián)圖像中可以追蹤的邊緣方向。有四種可能的方向來(lái)描述周?chē)南袼兀? 度、45 度、90 度和 135 度。我們將所有方向分配給這些角度中的任何一個(gè)。

          步驟 2:應(yīng)用非極大值抑制

          找到邊緣方向后,我們會(huì)做一個(gè)非極大值抑制算法。非極大值抑制沿邊緣方向跟蹤左右像素,如果當(dāng)前像素幅度小于左右像素幅度,則抑制當(dāng)前像素幅度。這將導(dǎo)致圖像變薄。

          for( i = 1; i < Ssize.height-1; i++ ){    for( j = 1; j < Ssize.width-1; j++ )    {        switch ( orients[count] )        {            case 0:                leftPixel  = magMat[i][j-1];                rightPixel = magMat[i][j+1];                break;            case 45:                leftPixel  = magMat[i-1][j+1];                rightPixel = magMat[i+1][j-1];                break;            case 90:                leftPixel  = magMat[i-1][j];                rightPixel = magMat[i+1][j];                break;            case 135:                leftPixel  = magMat[i-1][j-1];                rightPixel = magMat[i+1][j+1];                break;        }        // compare current pixels value with adjacent pixels        if (( magMat[i][j] < leftPixel ) || (magMat[i][j] < rightPixel ) )            (nmsEdges->data.ptr + nmsEdges->step*i)[j]=0;        Else            (nmsEdges->data.ptr + nmsEdges->step*i)[j]=                                 (uchar)(magMat[i][j]/MaxGradient*255);        count++;    }}

          第三步:做滯后閾值

          用滯后做閾值需要兩個(gè)閾值:高和低。我們應(yīng)用高閾值來(lái)標(biāo)記那些我們可以相當(dāng)確定是真實(shí)的邊緣。從這些開(kāi)始,使用先前導(dǎo)出的方向信息,可以通過(guò)圖像追蹤其他邊緣。在跟蹤邊緣時(shí),我們應(yīng)用較低的閾值,只要我們找到一個(gè)起點(diǎn),我們就可以跟蹤邊緣的微弱部分。

          _sdx = (short*)(gx->data.ptr + gx->step*i);_sdy = (short*)(gy->data.ptr + gy->step*i);fdx = _sdx[j]; fdy = _sdy[j];    MagG = sqrt(fdx*fdx + fdy*fdy); //Magnitude = Sqrt(gx^2 +gy^2)DirG =cvFastArctan((float)fdy,(float)fdx);     //Direction = tan(y/x)
          ////((uchar*)(imgGDir->imageData + imgGDir->widthStep*i))[j]= MagG;flag=1;if(((double)((nmsEdges->data.ptr + nmsEdges->step*i))[j]) < maxContrast){ if(((double)((nmsEdges->data.ptr + nmsEdges->step*i))[j])< minContrast) { (nmsEdges->data.ptr + nmsEdges->step*i)[j]=0; flag=0; // remove from edge ////((uchar*)(imgGDir->imageData + imgGDir->widthStep*i))[j]=0; } else { // if any of 8 neighboring pixel is not greater than max contraxt remove from edge if( (((double)((nmsEdges->data.ptr + nmsEdges->step*(i-1)))[j-1]) < maxContrast) && (((double)((nmsEdges->data.ptr + nmsEdges->step*(i-1)))[j]) < maxContrast) && (((double)((nmsEdges->data.ptr + nmsEdges->step*(i-1)))[j+1]) < maxContrast) && (((double)((nmsEdges->data.ptr + nmsEdges->step*i))[j-1]) < maxContrast) && (((double)((nmsEdges->data.ptr + nmsEdges->step*i))[j+1]) < maxContrast) && (((double)((nmsEdges->data.ptr + nmsEdges->step*(i+1)))[j-1]) < maxContrast) && (((double)((nmsEdges->data.ptr + nmsEdges->step*(i+1)))[j]) < maxContrast) && (((double)((nmsEdges->data.ptr + nmsEdges->step*(i+1)))[j+1]) < maxContrast)) { (nmsEdges->data.ptr + nmsEdges->step*i)[j]=0; flag=0; ////((uchar*)(imgGDir->imageData + imgGDir->widthStep*i))[j]=0; } }}

          第 4 步:保存數(shù)據(jù)集

          提取邊緣后,我們將所選邊緣的 X 和 Y 導(dǎo)數(shù)與坐標(biāo)信息一起保存為模板模型。這些坐標(biāo)將重新排列以反映作為重心的起點(diǎn)。

          找到基于邊的模板模型

          算法中的下一個(gè)任務(wù)是使用模板模型在搜索圖像中找到對(duì)象。我們可以看到我們從包含一組點(diǎn)的模板圖像創(chuàng)建的模型: 

          ,以及它在 X 和 Y 方向上的梯度 

          ,其中i = 1…n,n是模板 (T) 數(shù)據(jù)集中的元素?cái)?shù)。

          我們還可以在搜索圖像 (S) 中找到梯度 

          ,其中 u = 1...搜索圖像中的行數(shù),v = 1...搜索圖像中的列數(shù)。

          在匹配過(guò)程中,應(yīng)使用相似性度量將模板模型與所有位置的搜索圖像進(jìn)行比較。相似性度量背后的思想是取模板圖像梯度向量的所有歸一化點(diǎn)積之和,并在模型數(shù)據(jù)集中的所有點(diǎn)上搜索圖像。這會(huì)導(dǎo)致搜索圖像中每個(gè)點(diǎn)的分?jǐn)?shù)。這可以表述如下:

          如果模板模型和搜索圖像之間存在完美匹配,則此函數(shù)將返回分?jǐn)?shù) 1。該分?jǐn)?shù)對(duì)應(yīng)于搜索圖像中可見(jiàn)的對(duì)象部分。如果搜索圖像中不存在對(duì)象,則分?jǐn)?shù)將為 0。

          cvSobel( src, Sdx, 1, 0, 3 );  // find X derivativescvSobel( src, Sdy, 0, 1, 3 ); // find Y derivativesfor( i = 0; i < Ssize.height; i++ ){    for( j = 0; j < Ssize.width; j++ )    {         partialSum = 0; // initilize partialSum measure        for(m=0;m<noOfCordinates;m++)        {            curX    = i + cordinates[m].x ;    // template X coordinate            curY    = j + cordinates[m].y ; // template Y coordinate            iTx    = edgeDerivativeX[m];    // template X derivative            iTy    = edgeDerivativeY[m];    // template Y derivative
          if(curX<0 ||curY<0||curX>Ssize.height-1 ||curY>Ssize.width-1) continue; _Sdx = (short*)(Sdx->data.ptr + Sdx->step*(curX)); _Sdy = (short*)(Sdy->data.ptr + Sdy->step*(curX)); iSx=_Sdx[curY]; // get curresponding X derivative from source image iSy=_Sdy[curY];// get curresponding Y derivative from source image if((iSx!=0 || iSy!=0) && (iTx!=0 || iTy!=0)) { //partial Sum = Sum of(((Source X derivative* Template X drivative) //+ Source Y derivative * Template Y derivative)) / Edge //magnitude of(Template)* edge magnitude of(Source)) partialSum = partialSum + ((iSx*iTx)+(iSy*iTy))* (edgeMagnitude[m] * matGradMag[curX][curY]); }

          在實(shí)際情況下,我們需要加快搜索過(guò)程。這可以使用各種方法來(lái)實(shí)現(xiàn)。第一種方法是使用平均的屬性。在尋找相似性度量時(shí),如果我們可以為相似性度量設(shè)置一個(gè)最小分?jǐn)?shù)(S min,我們就不需要評(píng)估模板模型中的所有點(diǎn)為了檢查特定點(diǎn) J 處的部分分?jǐn)?shù) S u,v,我們必須找到部分總和 Sm。點(diǎn) m 處的 Sm 可以定義如下:

          很明顯,和的剩余項(xiàng)小于或等于 1。因此,如果 ,我們可以停止評(píng)估 


          另一個(gè)標(biāo)準(zhǔn)可以是任何點(diǎn)的部分分?jǐn)?shù)應(yīng)大于最低分?jǐn)?shù)。即, 

          使用此條件時(shí),匹配將非常快。但問(wèn)題是,如果先檢查對(duì)象的缺失部分,部分和會(huì)很低。在這種情況下,對(duì)象的該實(shí)例不會(huì)被視為匹配項(xiàng)。我們可以用另一個(gè)標(biāo)準(zhǔn)修改它,我們用安全停止標(biāo)準(zhǔn)檢查模板模型的第一部分,用硬標(biāo)準(zhǔn)檢查其余部分, 

          用戶可以指定貪婪參數(shù) (g),其中使用硬標(biāo)準(zhǔn)檢查模板模型的部分。所以如果g=1,模板模型中的所有點(diǎn)都用硬標(biāo)準(zhǔn)檢查,如果g=0,所有點(diǎn)將只用安全標(biāo)準(zhǔn)檢查。我們可以將這個(gè)過(guò)程表述如下。

          部分分?jǐn)?shù)的評(píng)估可以在以下位置停止:

          // stoping criterias to search for modeldouble normMinScore = minScore /noOfCordinates; // precompute minumum score double normGreediness = ((1- greediness * minScore)/(1-greediness)) /noOfCordinates;// precompute greedniness
          sumOfCoords = m + 1;partialScore = partialSum /sumOfCoords ;// check termination criteria// if partial score score is less than the score than// needed to make the required score at that position// break serching at that coordinate.if( partialScore < (MIN((minScore -1) + normGreediness*sumOfCoords,normMinScore* sumOfCoords))) break;

          這種相似性度量有幾個(gè)優(yōu)點(diǎn):相似性度量對(duì)非線性光照變化是不變的,因?yàn)樗刑荻认蛄慷际菤w一化的。由于邊緣過(guò)濾沒(méi)有分割,它將顯示對(duì)光照任意變化的真實(shí)不變性。更重要的是,當(dāng)對(duì)象部分可見(jiàn)或與其他對(duì)象混合時(shí),這種相似性度量是穩(wěn)健的。

          增強(qiáng)功能

          該算法有多種可能的增強(qiáng)。為了進(jìn)一步加快搜索過(guò)程,可以使用金字塔方法。在這種情況下,搜索以低分辨率和小圖像尺寸開(kāi)始。這對(duì)應(yīng)于金字塔的頂部。如果在此階段搜索成功,則在金字塔的下一層繼續(xù)搜索,該層代表更高分辨率的圖像。以這種方式,繼續(xù)搜索,從而細(xì)化結(jié)果,直到達(dá)到原始圖像大小,即到達(dá)金字塔底部。

          通過(guò)擴(kuò)展旋轉(zhuǎn)和縮放算法,可以實(shí)現(xiàn)另一種增強(qiáng)。這可以通過(guò)創(chuàng)建用于旋轉(zhuǎn)和縮放的模板模型并使用所有這些模板模型執(zhí)行搜索來(lái)完成。

          參考

          1. 機(jī)器視覺(jué)算法和應(yīng)用 [Carsten Steger、Markus Ulrich、Christian Wiedemann]

          2. 數(shù)字圖像處理 [Rafael C. Gonzalez, Richard Eugene Woods]

          3. http://dasl.mem.drexel.edu/alumni/bGreen/www.pages.drexel.edu/_weg22/can_tut.html

          源碼與測(cè)試Demo

          1. 源碼下載鏈接:https://www.codeproject.com/KB/graphics/Edge_Based_template_match/GeoMatch_src.zip

          2. 測(cè)試Demo下載鏈接

          https://www.codeproject.com/KB/graphics/Edge_Based_template_match/GeoMatch_demo.zip



          【后記】

          1.  上面代碼使用的是OpenCV2版本,安裝包可以在下面交流群獲取

          2.  代碼適用部分遮擋和亮度變化情況的匹配;

          3.  算法測(cè)試時(shí)間較長(zhǎng),還需優(yōu)化,可用作學(xué)習(xí)。

          4.  不適用旋轉(zhuǎn)和縮放匹配;

          5.  和Halcon的匹配相比還有較大差距(如果有人拿這個(gè)說(shuō)實(shí)現(xiàn)了Halcon匹配算法,那估計(jì)是自己根本沒(méi)用過(guò)Halcon吧)。
             
          下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程
          在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):擴(kuò)展模塊中文教程即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺(jué)、目標(biāo)跟蹤、生物視覺(jué)、超分辨率處理等二十多章內(nèi)容。

          下載2:Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目52講
          小白學(xué)視覺(jué)公眾號(hào)后臺(tái)回復(fù):Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目即可下載包括圖像分割、口罩檢測(cè)、車(chē)道線檢測(cè)、車(chē)輛計(jì)數(shù)、添加眼線、車(chē)牌識(shí)別、字符識(shí)別、情緒檢測(cè)、文本內(nèi)容提取、面部識(shí)別等31個(gè)視覺(jué)實(shí)戰(zhàn)項(xiàng)目,助力快速學(xué)校計(jì)算機(jī)視覺(jué)。

          下載3:OpenCV實(shí)戰(zhàn)項(xiàng)目20講
          小白學(xué)視覺(jué)公眾號(hào)后臺(tái)回復(fù):OpenCV實(shí)戰(zhàn)項(xiàng)目20講即可下載含有20個(gè)基于OpenCV實(shí)現(xiàn)20個(gè)實(shí)戰(zhàn)項(xiàng)目,實(shí)現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。

          交流群


          歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺(jué)、傳感器自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺(jué)SLAM“。請(qǐng)按照格式備注,否則不予通過(guò)。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~


          瀏覽 385
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操笔视频国产 | 一级a片在线 | 91在线无码精品在线看 | 人妻免费视频 | 在线肏屄视频 |