python正十三边形_一起学python-opencv十三(直方图反向投影和模板匹配)
2D直方圖
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.html#twod-histogram
為什么只考慮h,s就夠了呢?
因為其實亮度是很容易受外界影響的,我們認為一個顏色的本質特征是h和s。計算2D直方圖,我們用的還是calcHist函數,不過參數得輸入兩個通道的了。H原來是0-360,為了讓8位能存下,就對應到了0-180。第四個參數是[xmin,xmax,ymin,ymax]這種形式的。x指的是行,y指的是列。
bins上面有很多規則,請大家大概看一下,說的是如果是一個int,那么兩個維度區間的數目都是int,如果是[int,int]這個兩個分別是兩個維度的bins個數,還有其它規則請自行查看。上面給出了range的格式[[xmin,xmax],[ymin,ymax]]。
返回的H是二維的直方圖分布,xedges是第一個維度的區間邊界組成的數組,yedges是第二個維度的。
上面應該是少了一句h,s,v=cv2.split(hsv)。下面是如何畫直方圖:
這個是可以大概看一下,越白的地方數值越高。其實有點像等高圖,不過我們這里最低是黑色,而不是藍色。還有就是用matpltlib畫圖了:
還參考了https://blog.csdn.net/goldxwang/article/details/76855200
imshow里的interpolation參數是插值的意思,為什么需要插值呢?因為我們的hist只提供了整數點的值而沒有提供中間的值,那么這些值該怎么補充呢?這時候就需要用到插值。
插值方式有很多種,上面有列出來。blinear是雙線性插值。這個我們前面介紹過,還有一個nearest也很常用。參考了https://blog.csdn.net/ccblogger/article/details/72918354
這里是舉了一個例子:
默認用的應該就是這種插值,需要注意的是,最近鄰插值是還要四舍五入的。
當然計算機也不可能一個點一個點去算,那也是無數個點,肯定有一個最小單位。旁邊的這個類似于等高圖高度顏色帶的這個東西是colorbar生成的,plt.colorbar()要寫在plt.show()之前。
這里需要注意一下:
596*300=238400。
去掉中括號以后就不對了。和不知道為什么是800。
用np生成二維直方圖也是可以的,結果是一樣的。
減小分的區間數的話。圖看起來更明顯一些。
需要提醒的是左下角是可以看到對應的高度值的:
[4.02e+04]就是鼠標所在處的高度。
直方圖反投影
原理介紹:參考了https://blog.csdn.net/zyzhangyue/article/details/45827261
這個是一個滑動窗口,每次移動一個像素,然后計算窗口中圖像的直方圖和模板直方圖的相似度。
最后肯定是要閾值化的,相似度大于某一個值才認為是我們要的結果。
函數實現:
中間最重要的函數當然是calcBackProject了。
scale是比例。我來選一個模板,就是圈起來的那朵花。
大概在[34:73,234:263]這個范圍。
出來的dst就是如果和模板直方圖越接近(這個接近可能就是用的直方圖比較中的某一種距離來度量)結果數值越大,那么用灰度顯示也就會越白,當然我猜測這個函數里面是還有一些處理的,因為滑動窗口每次只滑動一個像素嘛,有很多像素就重合了,那么這些像素點的輸出值怎么辦呢?我猜想可能就是取平均了。注意中括號。
模板直方圖分的區間越少,也就是分的越粗,直方圖反投影得到的結果越連續,但是也能太大。20的效果還算不錯。
下面就分得太粗略了。
分得太細比較難匹配到。
我有點不懂為什么上面要對模板直方圖歸一化。alpha是歸一化范圍的下限,而beta是上限,normal_type是歸一化方法,有很多種,參考了:https://www.cnblogs.com/sddai/p/6250094.html
我們常用的是:
我試了一下,好像有點知道是個怎么回事了。
這個模板直方圖的歸一化的最大值好像和輸出的dst的最大值是一樣的,當300的話就是飽和的,會被認為是255,雖然不知道為什么有這樣的設定,這個得深究到下面的c++代碼了。我前面不加為什么可以呢?因為我選擇的模板直方圖的最大值271大于255。這算是一個巧合,是因為我選擇的模板圖像比較大,然后顏色又都比較偏白色。那么這個歸一化的語句最好還是加上去吧。
596*400和我們的原圖形狀是一樣的。
最終輸出的圖像其實有點不太理想,我們把它再閾值化一下,當然這個閾值該怎么選,這個需要自己測試。中間的那個cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))是一種形態學處理,我們先不管它。閾值操作:
0其實就代表的是表格中的第一種閾值化方式:
效果還不錯。把這個和原圖與一下。
我選的這個模板有點太白了,不太明顯。
我前面也說過,直方圖不能代表圖像的全部信息,因為它只包含強度信息,缺少了位置信息,所以上面匹配到的結果其實還是有很多不是我們想要的。下面是一種考慮了位置信息的匹配方式。
模板匹配
原理:模板匹配的原理其實很簡單,還是基于滑動窗口,一個像素一個像素的去移動,只不過上面我們計算的是圖像直方圖的相似度,我們這里是直接計算圖像的相似度,方法有好多種,參考了
https://blog.csdn.net/tsvico/article/details/78817096
計算起來其實挺麻煩的,有的時候我們就需要用到一些比較巧的辦法,比如說對于一些相乘項的求和,我們或許可以把其中一個調轉180,這個是為了湊成卷積的形式,然后根據卷積定理轉到頻域去計算離散的傅里葉變換相乘,然后再傅里葉反變換回來,這樣是會減小計算量的。
還有一種加快運算速度的方法叫做積分圖法。參考了
https://blog.csdn.net/yuan1125/article/details/70274515
就是從左上角開始累積像素值,最后生成一個圖,就叫積分圖。
一個區域的特征值就是這個區域里所有像素點對應強度的和。
上面原理和如何加快計算的方法,下面就是代碼的實驗了。
為什么輸出圖像的大小會變小呢?這是因為輸出的圖像其實是由上面的方法計算出來的相似度,輸出的結果其實只需要取從左上角開始取(W-w+1,H-h+1)就夠了,因為剩下的區域是不可能作為匹配區域的左上角的,因為不夠啊。為什么取左上角,因為底層的c++是這么寫的。
紅色代表目標圖片,藍色是模板圖片,紅色是輸出區域。
官方例子是個灰度圖像,shape[::-1是步長為-1,為什么要為-1呢?這是因為w寬度,也就是列數和h高度,行數的位置是反過來的,我們完全可以寫h,w=template.shape。官方也是有點皮。我們還是匹配那朵白玫瑰。我先來介紹幾個函數,首先是模板匹配的函數:
這里面的參數的英文單詞很常見了。templ是模板的意思。
這個函數是找出最大值,最小值以及對應的位置。上面這些比較方法應該都在c++里面由宏定義的。eval就是為了去掉引號,那一開始在method列表里面別加引號不就行了嗎?搞不懂。
plt.xticks是選x軸坐標刻度的,他這樣寫就是不要刻度。plt.suptitle是大標題,因為有幾個子圖嘛,所以會有一個大標題咯。我就改了四處。
400-29+1=372,598-38+1=559。
如果把xTicks和yTick里刪掉,那么就會有刻度了。這個第一種方法結果稍微有點不對。
這其實和模板匹配算法有關系,下面其實寫錯了,我畫紅線的話都是錯的,不用在意。
這種方法取的是應該是左圖中最亮的地方。那么這樣的算法為什么不是一樣的最大呢?
設想黑線是均值,然后紅色是模板,藍色是我設定的圖像,那么你說按照上面的公式是紅色和紅色的值大,還是紅色和藍色的值大呢?毫無疑問是紅色和藍色。上面的方法是判斷相關性的而不是相似性,所謂相關性就是你增大,我也增大,你減小我也減小,那么我們就叫做正相關,反之叫做負相關,和增大和減小前的值和增大或者減小了多少都無關,所以說這個模板匹配方法很不好。
這個匹配的是對的。也是取左圖中最亮的地方。這種方法才是1代表正相關,-1代表負相關,0代表線性無關。
為什么標準相關匹配結果就可以呢?我想用柯西不等式來說明問題
-1<=R(x,y)<=1,這個取等條件比較苛刻,是所有位置對應像素的強度成比例才可以,一般這種條件在圖像中也就是同一張圖才能達到這樣的條件了,至少在我們這張圖上是的。
這個也是取最亮的地方,也是稍微有一點偏差的。
這個匹配的結果也還好。
上面兩種方法的差別和上面的相似,只不過上面是減去了絕對值,這里沒有減去絕對值而已,還是用相關性不是相似度和柯西不等式來解釋。
這個是找最暗的。匹配的也不錯。
上面兩個是做差后平方和的結果,當然是同一張圖片的輸出區域最暗了。對于我們這張圖,六種里面四種匹配的都還不錯,但是都是有一些條件的,不過我覺得沒有標準化的那兩個相關性方法就不要用了,比較差。
一個模板匹配多個對象
這個不只是取一個最大的或者最小的了,而是規定一個閾值,這個閾值時自己設定的,可以找到多個對象。我們還是用上面的來做實驗。
閾值設為0.8也還是只能匹配到我們的原圖。
0.5的時候又出現一個新的區域。
0.45的時候就比較多了。
這里還要提醒一點,plt.imshow單通道的時候,選擇cmap='gray',也就是顏色圖取的是灰度圖才會和cv2顯示的一致。不然用的時它使用的不是灰度系統。
用的時什么image.cmap。不知道這是個什么東西,但是絕對不是灰度。如果時3維就沒事,因為它會直接用RGB。
沒使用灰度之前。
之后:
雖然不知道為什么顯示的一個黑一個白。
不過好歹時回到了灰度空間。我有點理解為什么全是黑的了。首先colorbar會讓plt.imshow按照我們的灰度值來。注釋了colorbar后:
不注釋:
感覺其實挺奇怪的,我的理解是plt.imshow單通道的時候必須要有一個對比才行,如果全是一種顏色,colorbar也算是一種對比的手段,這個時候顯示的是完美的按照灰度。如果不是一個值,顯示的是相對灰度,也就是里面的最大值就是白色,最小值是黑色,線性插值來顯示灰度值。
前面又出現了變量前加*號的操作。
這個以前其實也說過的,不過相信很多人都忘了,其實也包括我,233,這很符合遺忘規律嘛,忘了不要緊,復習一下:https://zhidao.baidu.com/question/2140001532025683868.html
那這里為什么還要反著來呢?其實很簡單了,這個其實是用rectangle畫畫的一個特性:
這個實驗我們可以看到,rectangle里面傳遞參數的時候是列在前的,行在后的,這可能是為了適應我們的x軸水平,y軸垂直,一般寫坐標都是(x,y)這樣的習慣。不過這和np的格式就反過來了,因為np是行在前,列在后。還有一點需要注意:頂點坐標必須是元組。
好的,馬上是十一了,但是休息是不可能休息的。
總結
以上是生活随笔為你收集整理的python正十三边形_一起学python-opencv十三(直方图反向投影和模板匹配)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python编程发展_编程的发展史及Py
- 下一篇: python框架django文档_Dja