1. 程式人生 > 其它 >C++ Primer學習筆記 - 執行時型別識別

C++ Primer學習筆記 - 執行時型別識別

OpenCV影象處理


幾何變換

影象縮放:cv.resize(src,dsize,fx=0,fy=0,interpolation=cv.INTER_LINEAR)

src:輸入影象。

dsize:絕對尺寸,直接指定調整後圖像的大小。

fx,fy:相對尺寸,將dsize設定為None,然後將fx和fy設定為比例因子即可。

interpolation:插值方法。其中INTER_LINEAR:雙線性插值法;INTER_NEAREST:最近鄰插值;INTER_AREA:畫素區域重取樣(預設);INTER_CUBIC:雙三次插值。

影象平移:

將影象按照指定方向和距離,移動到相應的位置。

cv.warpAffine(img,M,dsize)

img:要操作的影象

M:2*3移動舉證,對於(x,y)處的畫素點,要把它移動到(x+tx,y+ty)處時,M矩陣應如下設定:

注意:將M設定為np.float32型別的Numpy陣列。

dsize:輸出影象的大小。

注意:輸出影象的大小,他應該是(寬度,高度)的形式。請記住,width=列數,height=行數。

影象旋轉:

指影象按照某個位置轉動一定角度的過程。旋轉中圖片仍保持原始尺寸。

OpenCV中影象旋轉首先根據旋轉角度和旋轉中心獲取旋轉矩陣,然後根據旋轉矩陣進行變換,即可實現任意角度和任意中心的旋轉效果。

API:cv.getRotationMatrix2D(center,angle,scale)

center:旋轉中心。

angle:旋轉角度。

scale:縮放比例。

返回:

M:旋轉矩陣。

呼叫cv.warpAffine完成影象的旋轉。

仿射變換

影象的仿射變換涉及到影象的形狀位置角度的變化,主要是對影象進行縮放,旋轉,翻轉,平移等操作。

在仿射變換中,原圖中所有的平行線在結果影象中同樣平行。為了建立這個矩陣我們需要從原影象中找到三個點以及他們在輸出影象中的位置。然後使用cv.getAffineTransform會建立一個2×3的矩陣,最後這個矩陣會被傳給函式cv.warpAffine。

投射變換

利用透視中心、像點、目標點三點共線的條件,按透視旋轉定律使承影面(透視面)繞跡線(透視軸)旋轉某一角度,破壞原有的投影光纖束,仍能保持承影面上投影的幾何圖形不變的變換。

在OpenCV中,我們要找到4個點,其中任意三個點不共線,然後獲取變換矩陣T,再進行透射變換,通過函式cv.getPerspectiveTransform找到變換矩陣,將cv。warpPerspective應用於此3×3變換矩陣。

import cv2
import matplotlib.pyplot as plt
import numpy as np

lena1=cv2.imread("1.jpg")
cv2.imshow("image",lena1)
# cv2.waitKey(0)
#matplotlib中展示
plt.imshow(lena1[::-1,::-1,::-1])
plt.show()

px=lena1[100,100]
print(px)
lena2=cv2.imread("2.jpg")
lena2=cv2.resize(lena2,(800,1099))
img=cv2.add(lena1,lena2)
cv2.imshow("img",img)
img2=cv2.addWeighted(lena1,0.3,lena2,0.7,5)
cv2.imshow("img2",img2)
img3=cv2.resize(img2,(400,500),interpolation=cv2.INTER_CUBIC)
cv2.imshow("img3",img3)
rows,cols=img3.shape[:2]
M=np.float32([[1,0,100],[0,1,50]])
img4=cv2.warpAffine(img3,M,(rows,cols))
cv2.imshow("img4",img4)
M=cv2.getRotationMatrix2D((rows/2,cols/2),90,1)
img5=cv2.warpAffine(img3,M,(rows,cols))
cv2.imshow("img5",img5)
a1=np.float32([[50,50],[50,200],[200,50]])
a2=np.float32([[100,50],[50,200],[200,100]])
M1=cv2.getAffineTransform(a1,a2)
img6=cv2.warpAffine(img2,M1,(cols,rows))
cv2.imshow("img6",img6)
#透射變換
b1=np.float32([[32,12],[14,25],[23,32],[14,23]])
b2=np.float32([[44,23],[12,32],[22,32],[43,23]])
M2=cv2.getPerspectiveTransform(b1,b2)
img6=cv2.warpPerspective(img2,M2,(cols,rows))
cv2.imshow("img6",img6)
cv2.waitKey(0)

形態學操作

腐蝕

具體操作時用一個結構元素掃描影象中的每一個畫素,用結構元素中的每一個畫素與其覆蓋,畫素做“與”操作,如果都為1,則該畫素為1,否則為0。

該方法的作用是消除物體邊界點,使目標縮小,可以消除小於結構元素的噪聲點。

API:cv.erode(img,kernel,iterations)

img:要處理的影象

kernel:核結構

iterations:腐蝕的次數,預設是1

膨脹

用一個結構元素掃描影象中的每一個畫素,用結構元素中的每一個畫素與其覆蓋的畫素做“與”操作,如果都為0,則該畫素為0,否則為1。

該方法的作用是將與物體接觸的所有背景點合併到物體中,使目標增大,可添補目標中的孔洞。

API:cv.dilate(img,kernel,iterations)

#腐蝕和膨脹
kernel=np.ones((5,5),np.uint8)
img7=cv2.erode(img,kernel)
img8=cv2.dilate(img,kernel)
cv2.imshow("img7",img7)
cv2.imshow("img8",img8)
開閉運算

開運算和閉運算是腐蝕和膨脹按照一定的次序進行處理。但是兩者都是不可逆的,即先開後閉之後並不能得到原來的影象。

開運算:

先腐蝕後膨脹,作用是分離物體,消除小區域。特點是消除噪點,去除小的干擾塊,而不影響原來的影象。

閉運算:

先膨脹後腐蝕,作用是消除“閉合”物體裡面的孔洞,特點:可以填充閉合區域。

API:cv.morphologyEx(img,op,kernel)

img:要處理的影象

op:處理方式:若進行開運算,則設為cv.MORPH_OPEN,若進行閉運算,則設為cv.MORPH_CLOSE

kernel:核結構

禮帽和黑帽

禮帽運算:

原影象與”開運算“的結果圖之差。

黑帽運算:

“閉運算”結果圖與原影象之差。

API:cv.morphologyEx(img,op,kernel)

img:要處理的影象

op:處理方式。MORPH_CLOSE:閉運算;MORPH_OPEN:開運算;MORPH_TOPHAT:禮帽運算;MORPH_BLACKHAT:黑帽運算。

kernel:核結構。

影象平滑

影象噪聲

椒鹽噪聲

是影象中常見的一種噪聲,是一種隨機出現的白點或者黑點,可能是亮的區域有黑色畫素或者是暗的區域有白色畫素。成因可能是因為影像訊號受到突如其來的強烈干擾而產生、類比數位轉換器或位元傳輸錯誤等。例如失效的感應器導致畫素值為最小值,飽和的感應器導致畫素值為最大值。

高斯噪聲

指噪聲密度函式服從高斯分佈的一類噪聲。由於高斯噪聲在空間和頻域中數學上的易處理性,這種噪聲模型經常被用於實踐中。

高斯噪聲產生的噪聲是各個灰度值的都有,不僅僅是黑白兩種顏色。

影象平滑

去除影象中的高頻資訊,保留低頻資訊。

因此,實行低通濾波可以去除影象中的噪聲,對影象進行平滑處理。

濾波器可以分為:均值濾波,高斯濾波,中值濾波,雙邊濾波。

均值濾波

優點:演算法簡單,計算速度較快。

缺點是在去除噪聲的同時也去除了很多的細節部分,將影象變得模糊。

API:cv.blur(src,ksize,anchor,borderType)

src:輸入影象

ksize:卷積核的大小

anchor:預設值(-1,-1),表示核中心

borderType:邊界型別

高斯平滑

正態分佈是一種鐘形曲線,越接近中心,取值越大,越遠離中心,取值越小。計算平滑結果時,只需要將“中心點”作為原點,其他點按照其在正態曲線上的位置,分配權重,就可以得到一個加權平均值。

高斯平滑在處理影象中的高斯噪聲方面非常有效。

如果原圖是彩色影象,就對RGB三個通道分別都做一次高斯平滑就可以了。

API:cv.GaussianBlur(src,ksize,sigmax,sigmay,borderType)

src:輸入影象。

ksize:高斯卷積核大小,注意:卷積核的寬度和高度都應為奇數,且可以不同。

sigmax:水平方向的標準差

sigmay:垂直方向的標準差,預設值為0,表示為sigmax相同。

borderType:填充邊界型別

中值濾波

基本思想是用畫素點鄰域灰度值的中值來代替該畫素點的灰度值。

中值濾波對椒鹽噪聲來說尤其有用,因為它不依賴於鄰域內那些與典型值差別很大的值。

API:cv.medianBlur(src,ksize)

src:輸入影象。

ksize:卷積核的大小。

直方圖

影象直方圖是用以表示數字影象中亮度分佈的直方圖,標繪了影象中每個亮度值的畫素個數。這種直方圖中,橫座標的左側為較暗的區域,右側為較亮的區域。因此一張較暗圖片的直方圖中的資料多集中於左側和中間部分,而整體明亮、只有少量陰影的影象則相反。

直方圖的一些術語:

dims:需要統計的特徵數目。

bins:每個特徵空間子區段的數目。

range:要統計特徵的取值範圍。

直方圖的意義:

直方圖是影象中畫素強度分佈的圖形表達方式。

它統計了每個強度值所具有的畫素個數。

不同的影象的直方圖可能是相同的。

API:cv.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]])

images:原影象。當傳入函式時應該用中括號[]括起來。例如[img]

channels:如果輸入影象是灰度圖,它的值就是[0];如果是彩色影象的話,傳入的引數可以是[0],[1],[2]它們分別對應著通道B,G,R。

mask:掩模影象。要統計整幅影象的直方圖就把它設為None。但是如果你想統計影象某一部分的直方圖的話,你就需要製作一個掩模影象,並使用它。

histSize:BIN的數目。也應該用中括號括起來。

ranges:畫素值範圍,[0,255]

掩模的應用

掩模的主要用途:

  • 提取感興趣區域:用預先製作的感興趣區掩模與待處理影象進行“與”操作,得到感興趣區影象,感興趣區內影象值保持不變,而區外影象值都為0.

  • 遮蔽作用:用掩模對影象上某些區域作遮蔽,使其不參加處理或不參加處理引數的計算,或僅對遮蔽區做處理或統計。

  • 結構特徵提取:用相似性變數或影象匹配方法檢測和提取影象中與掩模相似的結構特徵。

  • 特殊形狀影象製作。

API:cv.bitwise_and(img,img,mask=mask)

直方圖均衡化

把原始影象的灰度直方圖從比較集中的某個灰度區間變成更廣泛灰度範圍內的分佈。直方圖均衡化就是對影象進行非線性拉伸,重新分配影象畫素值,使一定灰度範圍內的畫素數量大致相同。

這種方法能夠提高影象整體的對比度,特別是有用資料的畫素值分佈比較接近時,在X光影象中使用廣泛,可以提高骨架結構的顯示,另外在曝光過度或不足的影象中可以更好的突出細節。

API:cv.equalizeHist(img)

img:灰度影象

返回值:均衡化後的結果。

自適應直方圖均衡化

對整幅影象進行很多小塊劃分,然後對每一個小塊分別進行直方圖均衡化。如果有噪聲的話,噪聲會被方法,為了避免這種情況的出現要使用對比度限制。對於每個小塊來說,如果直方圖中的bin超過對比度的上限的話,就把其中的畫素點均勻分散到其他bins中,然後再進行直方圖均衡化。

最後,為了去除每一個小塊之間的邊界,再使用雙線性差值,對每一小塊進行拼接。

API:cv.createCLAHE(clipLimit,titleGridSize)

clipLimit:對比度限制,預設是40

titleGridSize:分塊的大小,預設為8×8

邊緣檢測

邊緣檢測的目的是標識數字影象中亮度變化明顯的點,影象屬性中的顯著變化通常反映了屬性的重要事件和變化。

影象邊緣檢測大幅度地減少了資料量,並剔除了可以認為不相關的資訊,保留了影象重要的結構屬性。有許多方法用於邊緣檢測,絕大部分可以劃分為兩類:基於搜尋和基於零穿越。

基於搜尋:通過尋找影象一階導數中的最大值來檢測邊界,然後利用計算結果估計邊緣的區域性方向,通常採用梯度的方向,並利用此方向找到區域性梯度模的最大值,代表演算法是Sobel運算元和Scharr運算元。

基於零穿越:通過尋找影象二階導數零穿越來尋找邊界,代表演算法是Laplacian運算元。

Sobel檢測運算元

Sobel邊緣檢測演算法比較簡單,實際應用中效率比canny邊緣檢測效率要高,但是邊緣不如Canny檢測的準確,但是很多實際應用的場合中,Sobel邊緣卻是首選,Sobel運算元是高斯平滑與微分操作的結合體,所以其抗噪聲能力很強,用途較多。尤其是效率要求較高,而對紋理不太關心的時候。

對於要處理的影象需要從兩個維度進行求導:水平變化和垂直變化。然後對兩個方向的結果進行平方和再開方。

統計極大值所在的位置,就是影象的邊緣。

注意:當核心大小為3時,以上Sobel核心可能產生比較明顯的誤差,為解決這一問題,我們使用Scharr函式,但該函式僅作用於大小為3的核心。該函式的運算與Sobel函式一樣快,但結果卻更加精確。

API:cv.Sobel(src,ddepth,dx,dy,dst,ksize,scale,delta,borderType)

src:傳入的影象

ddepth:影象的深度

dx和dy:指求導的階數,0表示這個方向上沒有求導,取值為0,1.

ksize:是Sobel運算元的大小,即卷積核的大小,必須為奇數1、3、5、7,預設為3。如果ksize=-1,就演變成為3×3的Scharr運算元。

scale:縮放導數的比例常數,預設情況為沒有伸縮係數。

borderType:影象邊界的模式,預設值為cv.BORDER_DEFAULT。

Sobel函式求導完後會有負值,還有會大於255的值。而原影象是uint8,即8位無符號數,所以Sobel建立的影象位數不夠,會有截斷。因此要使用16位有符號的資料型別,即cv.CV_16S。處理完影象後,再使用cv.convertScaleAbs()函式將其轉回原來的uint8格式,否則影象無法顯示。

Sobel運算元是在兩個方向計算的,最後還需要用cv.addWeighted()函式將其組合起來。

拉普拉斯運算元

拉普拉斯利用的是二階導數來進行邊緣檢測。

API:cv.Laplacian(src,ddepth[,dst[,kszie[,scale[,delta[,borderType]]]]])

Src:需要處理的影象。

Ddepth:影象的深度,-1表示採用的是原影象相同的深度,目標影象的深度必須大於等於原影象的深度;

ksize:運算元的大小,即卷積核的大小,必須為1,3,5,7.

Canny邊緣檢測

是一種非常流行的邊緣檢測演算法。

原理

第一步:去除噪聲

由於邊緣檢測很容易受到噪聲的影響,所以首先使用5×5高斯濾波器去除噪聲。

第二步:計算影象梯度

對於平滑後的影象使用Sobel運算元計算水平方向和豎直方向的一階導數(Gx和Gy)。根據得到的這兩幅梯度圖找到邊界的梯度和方向。

如果某個畫素點是邊緣,則其梯度方向總是垂直與邊緣。梯度方向被歸為四類:垂直,水平,和兩個對角線方向。

第三步:非極大值抑制

在獲得梯度的方向和大小後,對整幅影象進行掃描,去除那些非邊界上的點。對每一個畫素進行檢查,看這個點的梯度是不是周圍具有相同梯度方向的點中最大的。

第四步:滯後閾值

現在要確定真正的邊界,設定兩個閾值max和min。當影象的灰度梯度高於max時被認為是真的邊界,低於min時會被拋棄。如果介於兩者之間的話,要看這兩個點是否與某個被確定為真正的邊界相連。

API:cv.Canny(image,threshold1,threshold2)

image:灰度圖

threshold1:min,較小的閾值將間斷的邊緣連線起來

threshold2:max,較大的閾值檢測影象中明顯的邊緣

模板匹配和霍夫變換

模板匹配就是在給定的圖片中查詢和模板最相似的區域,該演算法的輸入包括模板和圖片。整個任務過程就是不斷地滑動模板圖片來尋找與模板相同的圖片區域。最終將匹配度最高的區域選擇為最終的結果。

API:cv.matchTemplate(img,template,method)

img:要進行模板匹配的影象

template:模板

method:實現模板匹配的演算法,主要有:平方差匹配(CV_TM_SQDIFF)想、相關匹配(CV_TM_CCORR)、利用相關係數匹配(CV_TM_CCOEFF)

最後使用minMaxLoc定位最匹配的區域。

模板匹配不適用於尺度變換,視角變換後的影象。

霍夫變換

常用來提取影象中的直線和圓等幾何形狀。

笛卡爾座標系中的一條直線,對應於霍夫空間中的一個點。

API:cv.HoughLines(img,rho,theta,threshold)

img:檢測的影象,要求是二值化的影象,所以在呼叫霍夫變換之前首先要進行二值化,或者進行Canny邊緣檢測。

tho、theta:ρ和角度的精確度。

threshold:閾值,只有累加器中的值高於該閾值時才被認為是直線。

霍夫圓檢測

霍夫梯度法將霍夫圓檢測分為兩個階段,第一階段檢測圓心,第二階段利用圓心推匯出圓半徑。

  • 圓心檢測的原理:圓心是圓周法線的交匯處,設定一個閾值,在某點的相交的直線條數大於這個閾值就認為該交匯點為圓心。

  • 圓半徑確定原理:圓心到圓周上的距離是相同的,確定一個閾值,只要相同距離的數量大於該閾值,就認為該距離是該圓心的半徑。

原則上霍夫變換可以檢測任何形狀,但複雜的形狀需要的引數更多,霍夫空間的維數就更多,因此程式實現上所需的記憶體空間以及執行效率上都不利於把標準霍夫變換應用於實際複雜圖形的檢測中。霍夫梯度法是霍夫變換的改進,它的目的是減小霍夫空間的維度,提高效率。

API:cv.HoughCircles(image,method,dp,minDist,param1=100,param2=100,minRadiius=0,maxRadius=0)

image:輸入影象,應輸入灰度影象。

method:使用霍夫變換圓檢測的演算法,它的引數是CV_HOUGH_GRADIENT。

dp:霍夫空間的解析度,dp=1時表示霍夫空間與輸入影象空間的大小一致,dp=2時霍夫空間是輸入影象空間的一般,以此類推。

minDist:表示圓心之間的最下距離,如果檢測到的兩個圓心之間距離小於該值,則認為它們是同一個圓心。

param1:邊緣檢測時使用Canny運算元的高閾值,低閾值是高閾值的一半。

param2:檢測圓心和確定半徑時所共有的閾值。

minRadius和maxRadius:所檢測到的圓半徑的最小值和最大值。

霍夫圓檢測對噪聲比較敏感,因此要對影象進行中值濾波。