OpenCV圖像變換二 投影變換與極座標變換實現圓形圖像修正

投影變換

在放射變換中,物體是在二維空間中變換的。若是物體在三維空間中發生了旋轉,那麼這種變換就成爲投影變換,在投影變換中就會出現陰影或者遮擋,咱們能夠運用二維投影對三維投影變換進行模塊化,來處理陰影或者遮擋。在OpenCV中有相似於getAffineTransform函數:getPerspectiveTransform(src,dst)函數 用來處理計算投影變換矩陣。與getAffineTransform函數不一樣的是傳入的參數是三維空間座標系的空間座標,也就是4*2的二維ndarray,其中每一行表明一個座標而且傳入的數據類型必須爲float32.示例:數組

import cv2
import numpy as np
src=np.array([[0,0],[100,0],[0,100],[100,100]],np.float32)
dst=np.array([[100,10],[100,10],[50,70],[200,150]],np.float32)
P=cv2.getPerspectiveTransform(src,dst)
print(P)

運行結果:app

[[-7.77156117e-16 -1.00000000e+00  1.00000000e+02]
 [-2.77555756e-15 -1.00000000e-01  1.00000000e+01]
 [-2.66713734e-17 -1.00000000e-02  1.00000000e+00]]

由結果能夠看出當前輸出的類型是float64.對於仿射變換在OpenCV中提供了以下的函數
cv2.warpPerspective(src,M,dsize[,dst[,flags[,borderMode[,borderValue]]]])
輸入的矩陣類型是3行3列的投影變換矩陣。示例:模塊化

import cv2
import numpy as np
import matplotlib


def Perspect(path):
    img=cv2.imread(path,cv2.IMREAD_GRAYSCALE)
    if not isinstance(img, np.ndarray):
        print('PASS')
        pass
    else:
        h,w=img.shape
       #設置變換座標變化
        src=np.array([[0,0],[w-1,0],[0,h-1],[w-1,h-1]],np.float32)
        dst=np.array([[100,100],[w/3,100],[100,h-1],[w-1,h-1]],np.float32)
        #計算投影變換矩陣
        P=cv2.getPerspectiveTransform(src,dst)
        #利用變化矩陣進行投影變換
        r=cv2.warpPerspective(img,P,(w,h),borderValue=126)
        #顯示圖像
        cv2.imshow('A',img )
        cv2.imshow('B',r)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        print(P)
Perspect('img/aa.jpg')

極座標變換

極座標變換主要處理校訂圖像中的圓形物體或者在圓形中物體函數

1.將笛卡爾座標轉換爲極座標

\(r=\sqrt{(x-(\overline{x})^2)+(y-(\overline{y})^2)}\)
\[\theta= \left\{ \begin{matrix} 2\pi +arctan2(y-\overline{y},x-\overline{x}), &y-\overline{y}\leq0\\ arctan2(y-\overline{y},x-\overline{x},&y-\overline{y}>0 \end{matrix} \right\} \]
以變換中心爲圓心的同一個圓心上的點,在極座標系\(\theta\)or中顯示爲一條直線。其中\(\theta\)的取值範圍爲[0,2\(\pi\)],函數arctan2返回的角度和笛卡爾積座標點所在的象限有關係。舉例,(9,15)以(2,10)爲中心進行極座標的變換,示例代碼:
#半徑轉換 r=math.sqrt(math.pow(9-2,2)+math.pow(15-10,2)); #角度轉換 theta=math.atan2(15-10,9-2)/math.pi*180
該示例能夠這樣理解,先把座標原點移動到(2,10)處,則(9,15)平移後的座標變爲(7,5),而後再以(0,0)爲中心進行轉換。在OpenCV中的函數cartToPolar(x,y[,magnitude[, angle[,angleIndegress ]]])實現的就是將原點移動到變換中心後的笛卡爾積座標向極座標的變換,返回值magnitude,angle是與參數x,y具備相同尺寸和數據類型的ndarray。angleInDegrees的值爲True時,返回值爲角度,反之返回值爲弧度。
例如:計算(0,0)、(1,0)、(2,0)、(0,1)、(1,1)、(2,1)、(0,2)、(1,2)、(2,2)這九個點以(1,1)爲中心進行的座標轉換。首先將座標原點移動到(1,1)處,按照平移放射矩陣計算出這九個點平移後的新座標值,而後利用函數cartToPolar進行極座標的轉換。代碼表示爲:spa

import cv2
import numpy as np
x=np.array([[0,1,2],[0,1,2],[0,1,2]],np.float64)-1
y=np.array([[0,0,0],[1,1,1],[2,2,2]],np.float64)-1
r,theta = cv2.cartToPolar(x,y,angleInDegrees=True)
print("r: %s"%r)
print("theta: %s"%theta)

運行結果:
在這裏插入圖片描述能夠看到執行後的極座標(\(\theta\),r)
以上九個點的圖像表示就是以(1,1)爲圓心的九個點,距離變換中心相等的點轉換爲極座標後在極座標系中位於同一條直線上。這樣就直觀的給出了極座標變換是如何校訂圖像中的圓形物體或者圓環中的物體的。code

2.將極座標轉換爲笛卡兒座標

極座標的變換是可逆的,在已知極座標和笛卡兒座標的條件下,計算哪一個笛卡兒座標以(\(\overline{x}\),\(\overline{y}\))爲中心的極座標變換時(\(\theta\),r),計算公式爲:
\[ x= \overline{x}+rcos\theta, y=\overline{y}+rsin\theta\]
在OpenCV中的實現函數是 cv2.polarToCart(magnitude,angle[,x[, y[, angleInDegrees ]]] )來實現將極座標轉化爲笛卡爾座標。其參數與cartToPolar參數相似。代碼舉例 實現 根據極座標系的(30,20),(31,21),(30,10),(30,10)四個點計算迪卡兒座標系的哪四個點以(-6,6)爲中心變換獲得的。orm

import cv2
import numpy as np
 # 將迪卡兒座標轉換爲極座標
angle = np.array([[30, 31], [30, 30]], np.float32)
r = np.array([[20, 21], [10, 10]], np.float32)
x, y = cv2.polarToCart(r, angle, angleInDegrees=True)
print("變換中心爲(0,0) 獲得的四個迪卡兒座標")
print("x: %s" % x)
print("y: %s" % y)

x+=-6
y+=6
print("變換中心爲(-6,6) 獲得的四個迪卡兒座標")
print("x: %s" % x)
print("y: %s" % y)

運行結果:
在這裏插入圖片描述blog

3.利用極座標變換實現圖像修正

咱們利用極座標和迪卡兒座標的意義對應關係獲得O的每個像素值:
\[O(r,\theta)=f_{1}( \overline{x}+rcos\theta,\overline{y}+rsin\theta)\]
此公式中的圖像輸出是以1爲步長進行離散化的,可是這樣的化輸出的圖像矩陣會出現失真的狀況,丟失跟多的圖像信息,。咱們的解決方法是將與(\(\overline{x}\),\(\overline{y}\))的距離範圍爲[\(r_{min}\),\(r_{max}\)]而且角度範圍在 \([\theta_{min},\theta_{max}]\)內的點進行極座標向笛卡爾座標的變換,而且進行離散化。\(\theta\)的變換步長\(\theta_{step}\)通常取\(\tfrac{360}{180*N}\),N\(\ge\) 2,此時輸出的寬爲w \(\approx\) \(\tfrac{r_{max}-r_{min}}{r_{step}}\) 圖像矩陣的第i行第j列可經過如下的公式進行計算:
\[O(i,j)= F_1 (\overline{x}+(r_{min}+r_{step}i)* cos(\theta_{min}+\theta_{step}j),\overline{y}+(r_{min}+r_{step}i)*sin(\theta_{min}+\theta_{step}j)) \]圖片

下面咱們經過一個具體的實例來實現極座標的變換:將一個圓環圖像變成矩形圖像ip

import cv2
import numpy as np
import sys

#實現圖像的極座標的轉換 center表明及座標變換中心‘;r是一個二元元組,表明最大與最小的距離;theta表明角度範圍
#rstep表明步長; thetastap表明角度的變化步長
def polar(image,center,r,theta=(0,360),rstep=0.5,thetastep=360.0/(180*4)):
    #獲得距離的最小值、最大值
    minr,maxr=r
    #角度的最小範圍
    mintheta,maxtheta=theta
    #輸出圖像的高、寬 O:指定形狀類型的數組float64
    H=int((maxr-minr)/rstep)+1
    W=int((maxtheta-mintheta)/thetastep)+1
    O=125*np.ones((H,W),image.dtype)
    #極座標轉換  利用tile函數實現W*1鋪成的r個矩陣 並對生成的矩陣進行轉置
    r=np.linspace(minr,maxr,H)
    r=np.tile(r,(W,1))
    r=np.transpose(r)
    theta=np.linspace(mintheta,maxtheta,W)
    theta=np.tile(theta,(H,1))
    x,y=cv2.polarToCart(r,theta,angleInDegrees=True)
    #最近插值法
    for i in range(H):
        for j in range(W):
            px=int(round(x[i][j])+cx)
            py=int(round(y[i][j])+cy)
            if((px>=0 and px<=w-1) and (py>=0 and py<=h-1)):
                O[i][j]=image[py][px]

    return O

if __name__=="__main__":
    img = cv2.imread("img/yu.jpg", cv2.IMREAD_GRAYSCALE)
    # 傳入的圖像寬:600  高:400
    h, w = img.shape[:2]
    print("h:%s w:%s"%(h,w))
    # 極座標的變換中心(300,200)
    cx, cy = 300, 200
    # 圓的半徑爲10 顏色:灰 最小位數3
    cv2.circle(img, (int(cx), int(cy)), 10, (255, 0, 0, 0), 3)
    L = polar(img, (cx, cy), (100, 350))
    # 旋轉
    L = cv2.flip(L, 0)
    # 顯示與輸出
    cv2.imshow('img', img)
    cv2.imshow('O', L)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
相關文章
相關標籤/搜索