Numpy和OpenCV中的圖像幾何變換

2021-01-08 人工智慧遇見磐創

介紹

上面的圖像使它不言而喻什麼是幾何變換。它是一種應用廣泛的圖像處理技術。例如,在計算機圖形學中有一個簡單的用例,用於在較小或較大的屏幕上顯示圖形內容時簡單地重新縮放圖形內容。

它也可以應用於扭曲一個圖像到另一個圖像平面。例如,與其直視前方的場景,不如自上而下地看。在這個場景中應用透視圖變換來實現這一點。

另一個應用是訓練深層神經網絡。訓練深度模型需要大量的數據。在幾乎所有的情況下,模型都受益於更高的泛化性能,因為有更多的訓練圖像。人工生成更多數據的一種方法是對輸入數據隨機應用仿射變換(增強)。

在本文中,我將向你介紹一些變換,以及如何在Numpy和OpenCV中執行這些變換。特別是,我將關注二維仿射變換。你需要的是一些基本的線性代數知識。

仿射變換的類型

在不涉及太多數學細節的情況下,變換的行為由仿射A中的一些參數控制。

x』 = Ax

其中A是在齊次坐標系中的2x3矩陣或3x3,x是在齊次坐標系中的(x,y)或(x,y,1)形式的向量。這個公式表示A將任意向量x,映射到另一個向量x』。

一般來說,仿射變換有6個自由度。根據參數的值,它將在矩陣乘法後扭曲任何圖像。變換後的圖像保留了原始圖像中的平行直線(考慮剪切)。本質上,滿足這兩個條件的任何變換都是仿射的。

但是,有一些特殊形式的A,這是我們將要討論的。這包括旋轉、平移和縮放矩陣,如下圖所示。

上述仿射變換的一個非常有用的性質是它們是線性函數。它們保留了乘法和加法運算,並遵循疊加原理。

換言之,我們可以組合2個或更多的變換:向量加法表示平移,矩陣乘法表示線性映射,只要我們用齊次坐標表示它們。例如,我們可以將旋轉和平移表示為

A = array([[cos(angle), -sin(angle), tx], [sin(angle), cos(angle), ty], [0, 0, 1]])

圖像表示

在Python和OpenCV中,2D矩陣的原點位於左上角,從x,y=(0,0)開始。坐標系是左手的,X軸指向右,Y軸指向正下方。

但在教科書和文獻中,如上面所示的3個矩陣,大多數變換矩陣都遵循右手坐標系。因此,必須進行一些小的調整來調整軸線方向。

歐氏空間中的公共變換

在我們對圖像進行變換實驗之前,讓我們看看如何在點坐標上進行變換。因為它們本質上與圖像是網格中的二維坐標數組相同。

利用上面的知識,下面的代碼可以用來變換(0,0),(0,1),(1,0),(1,1)處的點。此外,Python還提供了一個有用的速記運算符@來表示矩陣乘法。

# 點生成器def get_grid(x, y, homogenous=False): coords = np.indices((x, y)).reshape(2, -1) return np.vstack((coords, np.ones(coords.shape[1]))) if homogenous else coords# 定義變換def get_rotation(angle): angle = np.radians(angle) return np.array([ [np.cos(angle), -np.sin(angle), 0], [np.sin(angle), np.cos(angle), 0], [0, 0, 1] ])def get_translation(tx, ty): return np.array([ [1, 0, tx], [0, 1, ty], [0, 0, 1] ])def get_scale(s): return np.array([ [s, 0, 0], [0, s, 0], [0, 0, 1] ])R1 = get_rotation(135)T1 = get_translation(-2, 2)S1 = get_scale(2)# 應用變換x'=Axcoords_rot = R1 @ coordscoords_trans = T1 @ coordscoords_scale = S1 @ coordscoords_composite1 = R1 @ T1 @ coordscoords_composite2 = T1 @ R1 @ coords

需要注意的是,除少數例外情況外,矩陣通常不進行交換。即

A1 @ A2 != A2 @ A1因此,對於變換

# 平移然後旋轉coords_composite1 = R1 @ T1 @ coords# 旋轉然後平移coords_composite2 = T1 @ R1 @ coords你將看到它們不會產生相同的映射,而且順序很重要。從右到左可以理解函數是如何應用的。

Numpy中的變換

現在對於圖片,有幾點需要注意。首先,如前所述,我們必須重新調整垂直軸。其次,變換後的點必須投影到圖像平面上。

實質上,需要採取的步驟是:

創建新圖像I'(x,y)以輸出變換應用變換將點投影到新的圖像平面上,僅考慮位於圖像邊界內的點。示例:圍繞圖像中心旋轉、縮放和平移

讓我們看一個變換,我們希望放大2倍,並圍繞圖像的中心位置旋轉45度。

這可以通過應用以下複合矩陣來實現。

height, width = image.shape[:2]tx, ty = np.array((width // 2, height // 2))angle = np.radians(45)scale = 2.0R = np.array([ [np.cos(angle), np.sin(angle), 0], [-np.sin(angle), np.cos(angle), 0], [0, 0, 1]])T = np.array([ [1, 0, tx], [0, 1, ty], [0, 0, 1]])S = np.array([ [scale, 0, 0], [0, scale, 0], [0, 0, 1]])A = T @ R @ S @ np.linalg.inv(T)應用於圖像

# 表示圖像坐標的網格coords = get_grid(width, height, True)x_ori, y_ori = coords[0], coords[1] # 應用變換warp_coords = np.round(A@coords).astype(np.int)xcoord2, ycoord2 = warp_coords[0, :], warp_coords[1, :]# 獲取圖像邊界內的像素indices = np.where((xcoord >= 0) & (xcoord < width) & (ycoord >= 0) & (ycoord < height))xpix2, ypix2 = xcoord2[indices], ycoord2[indices]xpix, ypix = x_ori[indices], y_ori[indices]# 將像素RGB數據映射到另一個數組中的新位置canvas = np.zeros_like(image)canvas[ypix, xpix] = image[yy, xx]在上面的兩個代碼片段中有幾點需要注意。

左手坐標系旋轉是通過交換符號來實現的。由於點圍繞原點旋轉,我們首先將中心平移到原點,然後再進行旋轉和縮放然後將點變換回圖像平面。將變換點捨入為整數以表示離散像素值。接下來,我們只考慮位於圖像邊界內的像素。映射對應的I(x,y)和I』(x,y)。如你所見,由於步驟4的原因,生成的圖像將有幾個鋸齒和孔。為了消除這種情況,開源庫使用插值技術來消除變換後的差異。

逆扭曲(Inverse Warping)

另一種防止上面情況的方法是將扭曲表示為給定扭曲點x'的源圖像I(x,y)的重採樣。這可以通過X'乘以A的逆來實現。這裡需要注意的是,變換必須是可逆的。

將變換的逆運算應用到X'上。X = np.linalg.inv(A) @ X'註:對於圖像,X'的逆扭曲只是將I'(X,y)重新投影到I(X,y)上。所以我們只需對I』(x,y)像素坐標進行逆變換,如下所示。

確定它在原始圖像平面中的位置對I(x,y)重新採樣RGB像素並將其映射回I'(x,y)# 設置像素坐標I'(x,y)coords = get_grid(width, height, True)x2, y2 = coords[0], coords[1]# 應用逆變換並捨入(最近鄰插值)warp_coords = (Ainv@coords).astype(np.int)x1, y1 = warp_coords[0, :], warp_coords[1, :]# 獲取圖像邊界內的像素indices = np.where((x1 >= 0) & (x1 < width) & (y1 >= 0) & (y1 < height))xpix1, ypix1 = x2[indices], y2[indices]xpix2, ypix2 = x1[indices], y1[indices]# 映射對應的像素canvas = np.zeros_like(image)canvas[ypix1, xpix1] = image[ypix2,xpix2]coords = get_grid(width, height, True)x2, y2 = coords[0], coords[1]運行上面的代碼應該可以得到一個密集的、無孔的圖像。

OpenCV中的變換

現在你已經對幾何變換有了更好的理解,大多數開發人員和研究人員通常省去了編寫所有這些變換的麻煩,而只需依賴優化的庫來執行任務。在OpenCV中進行仿射變換非常簡單。

有幾種方法可以做到。一種可能的方法是你可以自己編寫仿射變換,並調用cv2.warfaffine(image,A,output_shape)

下面的代碼顯示了整個仿射矩陣,它將給出與上面相同的結果。一個很好的練習就是自己推導公式!

def get_affine_cv(t, r, s): sin_theta = np.sin(r) cos_theta = np.cos(r) a_11 = s * cos_theta a_21 = -s * sin_theta a_12 = s * sin_theta a_22 = s * cos_theta a_13 = t[0] * (1 - s * cos_theta) - s * sin_theta * t[1] a_23 = t[1] * (1 - s * cos_theta) + s * sin_theta * t[0] return np.array([[a_11, a_12, a_13], [a_21, a_22, a_23]])A2 = get_affine_cv((tx, ty), angle, scale)warped = cv2.warpAffine(image, A2, (width, height))另一種方法是依賴OpenCV使用cv2.getRotationMatrix2D(center,angle,scale)返回仿射變換矩陣。此函數使用角度圍繞點中心旋轉圖像,並使用比例縮放圖像。

A3 = cv2.getRotationMatrix2D((tx, ty), np.rad2deg(angle), scale)warped = cv2.warpAffine(image, b3, (width, height), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=0)

總結

在本文中,我介紹了幾何變換的基本概念以及如何將其應用於圖像。許多先進的計算機視覺,如使用視覺裡程計和多視圖合成的slam,都依賴於最初的理解變換。我希望你能更好地理解這些公式是如何在庫中編寫和使用的。

相關焦點

  • OpenCV-Python 圖像的幾何變換|十四
    目標學習將不同的幾何變換應用到圖像上,如平移、旋轉、仿射變換等。你會看到這些函數: cv.getPerspectiveTransform變換OpenCV提供了兩個轉換函數cv.warpAffine和cv.warpPerspective,您可以使用它們進行各種轉換。
  • 乾貨|OpenCV看這篇就夠了,9段代碼詳解圖像變換基本操作
    OpenCV相比於其他的庫,最大的特點是對圖像的處理功能非常完備。OpenCV能夠實現對圖片顏色和形狀的變換。03 顏色變換圖片的顏色變換可以有很多種類,譬如可以對彩色圖片進行灰度化處理,調節圖片的亮度和對比度,將圖片轉換成負片的形式等。
  • OpenCV 之 霍夫變換
    Hough 變換,對圖像中直線的殘缺部分、噪聲、以及其它的共存結構不敏感,因此,具有很強的魯棒性。
  • 【數字圖像處理系列五】圖像濾波之空間濾波:圖像平滑降噪和圖像銳化
    圖像數據集增強方式總結和實現【數字圖像處理系列四】在圖像增強:線性、 分段線性、 對數、 反對數、 冪律(伽馬)變換、直方圖均衡【數字圖像處理系列三】一文中我們從圖像灰度變換的角度闡述了圖像增強的各種方式,本文我們將一起學習圖像處理中重點的方式:圖像濾波,圖像濾波分為空間域濾波和頻率域濾波,頻率域濾波我們將在下一節重點說明
  • OpenCV中的快速直線檢測
    本文範例運行環境FastLineDetectors運行必要條件FastLineDetectors屬於opencv-contrib中的模塊,需要安裝opencv-contrib-python。在python的opencv相關的安裝包中,opencv-python 包含主要模塊,opencv-contrib-python 包含主要模塊以及一些擴展模塊。但這兩個模塊並不兼容,如果已經安裝過opencv-python,需要先卸載,再安裝opencv-contrib-python。
  • 基於opencv 的圖像處理入門教程
    模糊圖片高斯模糊高斯模糊採用的是 GaussianBlur() 方法,採用高斯核,並且核的寬和高必須是正數,且是奇數。高斯濾波主要用於消除高斯噪聲,可以保留更多的圖像細節,經常被稱為最有用的濾波器。實現的代碼如下所示:中值模糊對於中值模糊,就是用區域內的中值來代替本像素值,因此孤立的斑點,比如 0 或者 255 的數值很容易消除掉。所以中值模糊主要用於消除椒鹽噪聲和斑點噪聲。
  • OpenCV-Python 直方圖-2:直方圖均衡|二十七
    因此,我們僅應用變換。img2 = cdf[img] 現在,我們像以前一樣計算其直方圖和cdf(您這樣做),結果如下所示:另一個重要的特徵是,即使圖像是一個較暗的圖像(而不是我們使用的一個較亮的圖像),經過均衡後,我們將得到幾乎相同的圖像。因此,這是作為一個「參考工具」,使所有的圖像具有相同的照明條件。
  • 深入理解OpenCV+Python直方圖均衡化
    直方圖均衡化是圖像處理領域中利用圖像直方圖對對比度進行調整的方法。
  • 以別墅圖片為例 結合numpy和OpenCV庫 探尋Python中數組組合方式
    前幾篇博文我們介紹了numpy的基礎知識numpy庫學習總結(基礎知識)和numpy中array數組的維度變化Python數據分析必備基本功 numpy數組維度變換的常用方法匯總。今天,我們來梳理一下numpy中數組array的組合操作。
  • opencv-python圖像預處理-濾波
    為了消除外界環境對圖像採集的幹擾,增強圖像的邊緣及灰度跳變的部分,使圖像變得清晰以及提高圖像處理速度需要對圖像進行預處理操作,主要是對圖像進行濾波和增強操作。使用的方法可以分為空間域處理和頻率域處理兩類。空間域指圖像平面本身,這類圖像處理方法用各種模板直接與圖像進行卷積運算,實現對圖像的處理。
  • OpenCV(四)邊緣檢測
    邊緣檢測的方法有很多,但是絕大部分都可以分為兩大類,第一類是基於搜索,也就是通過尋找圖像一階導數中的最大值和最小值來檢測邊界,通常是定位在梯度最大的方向。其次是基於零穿越的方法,其通過尋找圖像二階導數零穿越來尋找便捷,通常是Laplacian過零點或者非線性差分表示的過零點。
  • OpenCV-Python 傅立葉變換|三十
    對於圖像,使用2D離散傅立葉變換(DFT)查找頻域。一種稱為快速傅立葉變換(FFT)的快速算法用於DFT的計算。關於這些的詳細信息可以在任何圖像處理或信號處理教科書中找到。請參閱其他資源部分。您可以將圖像視為在兩個方向上採樣的信號。因此,在X和Y方向都進行傅立葉變換,可以得到圖像的頻率表示。更直觀地說,對於正弦信號,如果幅度在短時間內變化如此之快,則可以說它是高頻信號。如果變化緩慢,則為低頻信號。您可以將相同的想法擴展到圖像。圖像中的振幅在哪裡急劇變化?在邊緣點或噪聲。因此,可以說邊緣和噪聲是圖像中的高頻內容。
  • opencv-python獲取圖像:面向對象與面向過程
    這裡需要注意以下,opencv讀取圖片默認通道為BGR的格式,當在其他UI用戶界面顯示圖像時注意轉換一下通道順序,例如BGR轉換成RGB:Image1=cv2.cvtColor(image, cv2.COLOR_BGR2RGB)下面讀取一張圖片並顯示
  • 霍夫變換——形狀特徵提取算法:車道線檢測
    霍夫變換是用來辨別找出物件中的特徵,例如:線條。他的算法流程大致如下,給定一個物件、要辨別的形狀的種類,算法會在參數空間中執行投票來決定物體的形狀,而這是由累加空間(accumulator space)裡的局部最大值來決定。理論上,霍夫變換就是對於原圖上的每一個直線都在參數空間畫一條線,最終找出參數空間變換線比較密集的地方在對應回到xy 空間坐標系。
  • 談談OpenCV中的四邊形
    因為這些點是矩形區域拍攝圖像後識別得到的圖形的邊界點,所以我們要抽象出來這個矩形,也就是我們要反映出這個矩形。問題是在拍照的時候攝像頭可能不是正對著圖形的,那麼矩形就必然在圖像上反映為一個四邊形, 如下圖所示。那怎麼得到這個四邊形的四個頂點呢?使用經典圖像處理的算法的話可以使用OpenCV提供了幾個和矩形相關的函數接口。另一類就是使用機器學習類算法檢測定位四個角點。
  • 「python opencv視覺零基礎」十四、直方圖反向投影
    前文提醒:博主正在參加博客之星評比,成功入選Top200,現在暫居第九歡迎各位點擊了解更多幫我投票,非常感謝~目錄「python opencv 計算機視覺零基礎實戰」 第一節「python opencv視覺入門到實戰」二、格式與攝像頭「python opencv 視覺入門到實戰」 三、圖像編輯「python
  • ImagePy——UI界面支持開放插件的Python開源圖像處理框架
    ImagePy 是一款基於 imagej 等插件的圖像處理框架,它可以與 scipy.ndimage、scikit-image、opencv、simpleitk、mayavi 以及任何基於 numpy 的庫進行組合使用,其地址為 http://imagepy.org。
  • 圖像配準的前世今生:從人工設計特徵到深度學習
    經過配準後的 CT 掃描和核磁共振圖像在本文中,我們會重點關注在一張參考圖像和一張待配準圖像之間進行圖像配準的不同方法。我們不會選擇迭代式的/基於強度的方法,因為它們並不像本文中提到的方法這樣常用。傳統的基於特徵的方法自本世紀初以來,圖像配準主要使用傳統的基於特徵的方法。這些方法基於三個步驟:關鍵點檢測和特徵描述,特徵匹配,圖像變形。簡而言之,我們在兩幅圖像中選擇興趣點,將參考圖像中的每個興趣點和它在待配準圖像中的對應點關聯起來,然後對待批准圖像進行變換,這樣兩幅圖像就得以對齊。
  • OpenCV-Python SIFT尺度不變特徵變換|三十九
    很明顯,因為轉角在旋轉的圖像中也仍然是轉角。但是縮放呢?如果縮放圖像,則拐角可能不是角。例如,檢查下面的簡單圖像。在同一窗口中放大小窗口中小圖像中的拐角時,該角是平坦的。因此,Harris拐角不是尺度不變的。
  • 「python opencv視覺零到實戰」八、圖片選區操作
    一、學習目標了解什麼是ROI了解floodFill的使用方法如有錯誤歡迎指出~目錄「python opencv 計算機視覺零基礎實戰」 第一節「python opencv視覺入門到實戰」二、格式與攝像頭「python opencv 視覺入門到實戰」 三、圖像編輯「python opencv視覺入門到實戰