文章目錄
- 先言
- 一、圖像顏色空間轉換
- 1.RGB顏色空間
- 2.顏色加法
- 3.顏色加權加法
- 4.HSV顏色空間
- 5.圖像轉換(cvtColor())
- 二、灰度實驗
- 1.灰度圖
- 2.圖像灰度化(最大值法)
- 3.圖像灰度化(平均值法)
- 4.圖像灰度化(加權平均值法)
- 三、圖像二值化
- 1.閾值法(THRESH_BINARY)和反閾值法(THRESH_BINARY_INV)
- 2.截斷閾值法(THRESH_TRUNC)
- 3.低閾值零處理(THRESH_TOZERO)與超閾值零處理(THRESH_TOZERO_INV)
- 4.OTSU閾值法(threshold())
- 5.自適應二值化(adaptiveThreshold())
- 四、圖像鏡像翻轉與仿射變換
- 1.圖像翻轉(圖像鏡像旋轉)
- 2.圖像旋轉
- 3.圖像平移
- 4.圖像縮放
- 結語
先言
在計算機視覺任務中,圖像預處理是至關重要的一環。無論是目標檢測、人臉識別還是圖像分類,原始圖像數據往往需要經過一系列變換才能更好地被算法理解。OpenCV 提供了強大的圖像處理工具,幫助我們高效完成這些預處理操作。
本文將重點介紹 圖像顏色空間轉換、灰度化實驗、二值化處理、鏡像翻轉 和 仿射變換
等核心預處理技術,通過代碼示例和效果對比,帶你掌握如何用 OpenCV 優化圖像數據
一、圖像顏色空間轉換
OpenCV中,圖像色彩空間轉換是一個非常基礎且重要的操作,就是將圖像從一種顏色表示形式轉換為另一種表示形式的過程。通過將圖像從一個色彩空間轉換到另一個色彩空間,可以更好地進行特定類型的圖像處理和分析任務。常見的顏色空間包括RGB、HSV、YUV等。
-
色彩空間轉換的作用
-
提高圖像處理效果
-
節省計算資源
-
1.RGB顏色空間
在圖像處理中,最常見的就是RGB顏色空間。RGB顏色空間是我們接觸最多的顏色空間,是一種用于表示和顯示彩色圖像的一種顏色模型。RGB代表紅色(Red)、綠色(Green)和藍色(Blue),這三種顏色通過不同強度的光的組合來創建其他顏色,廣泛應用于我們的生活中,比如電視、電腦顯示屏以及上面實驗中所介紹的RGB彩色圖。
RGB顏色模型基于笛卡爾坐標系,如下圖所示,RGB原色值位于3個角上,二次色青色、紅色和黃色位于另外三個角上,黑色位于原點處,白色位于離原點最遠的角上。因為黑色在RGB三通道中表現為(0,0,0),所以映射到這里就是原點;而白色是(255,255,255),所以映射到這里就是三個坐標為最大值的點。
RGB顏色空間可以產生大約1600萬種顏色,幾乎包括了世界上的所有顏色,也就是說可以使用RGB顏色空間來生成任意一種顏色。
注意:在OpenCV中,顏色是以BGR的方式進行存儲的,而不是RGB,這也是上面紅色的像素值是(0,0,255)而不是(255,0,0)的原因。
2.顏色加法
你可以使用OpenCV的cv.add()函數把兩幅圖像相加,或者可以簡單地通過numpy操作添加兩個圖像,如res = img1 + img2。兩個圖像應該具有相同的大小和類型。
cv.add()
飽和運算:
import cv2 as cv
#讀取兩個圖像
cao = cv.imread("../images/cao.png")
pig = cv.imread("../images/pig.png")
#cv的飽和操作add(img1,img2)
dst1 = cv.add(cao,pig)
cv.imshow("add",dst1)
cv.waitKey(0)
cv.destroyAllWindows()
numpy 直接加法:
import cv2 as cv
import numpy as np#讀取圖像
cao = cv.imread("../images/cao.png")
pig = cv.imread("../images/pig.png")
#numpy直接相加,取模運算 對256取模 250+10=4
dst2 = cao+pig
cv.imshow("numpy",dst2)
cv.waitKey(0)
cv.destroyAllWindows()
OpenCV加法和Numpy加法之間存在差異。OpenCV的加法是飽和操作,而Numpy添加是模運算。
3.顏色加權加法
cv2.addWeighted(src1,alpha,src2,deta,gamma)
src1
、src2
:輸入圖像。alpha
、beta
:兩張圖象權重。gamma
:亮度調整值。gamma > 0
,圖像會變亮。gamma < 0
,圖像會變暗。gamma = 0
,則沒有額外的亮度調整。
這其實也是加法,但是不同的是兩幅圖像的權重不同,這就會給人一種混合或者透明的感覺。圖像混合的計算公式如下:
g(x) = (1?α)f0(x) + αf1(x)
通過修改 α 的值(0 → 1),可以實現非常炫酷的混合。
現在我們把兩幅圖混合在一起。第一幅圖的權重是0.7,第二幅圖的權重是0.3。函數cv2.addWeighted()可以按下面的公式對圖片進行混合操作。
dst = α?img1 + β?img2 + γ
示例:
import cv2 as cv
#讀取圖像
cao = cv.imread("../images/cao.png")
pig = cv.imread("../images/pig.png")
#加權顏色加法cv.addWeighted(img1,alpha,img2,beta,gamma)
dst3 = cv.addWeighted(cao,0.5,pig,0.6,15)
cv.imshow("addWeighted",dst3)
cv.waitKey(0)
cv.destroyAllWindows()
4.HSV顏色空間
HSV顏色空間指的是HSV顏色模型,這是一種與RGB顏色模型并列的顏色空間表示法。RGB顏色模型使用紅、綠、藍三原色的強度來表示顏色,是一種加色法模型,即顏色的混合是添加三原色的強度。而HSV顏色空間使用色調(Hue)、飽和度(Saturation)和亮度(Value)三個參數來表示顏色,色調H表示顏色的種類,如紅色、綠色、藍色等;飽和度表示顏色的純度或強度,如紅色越純,飽和度就越高;亮度表示顏色的明暗程度,如黑色比白色亮度低。
HSV顏色模型是一種六角錐體模型,如下圖所示:
色調H:
使用角度度量,取值范圍為0°~360°,從紅色開始按逆時針方向計算,紅色為0°,綠色為120°,藍色為240°。它們的補色是:黃色為60°,青色為180°,紫色為300°。通過改變H的值,可以選擇不同的顏色
飽和度S:
飽和度S表示顏色接近光譜色的程度。一種顏色可以看成是某種光譜色與白色混合的結果。其中光譜色所占的比例越大,顏色接近光譜色的程度就越高,顏色的飽和度就越高。飽和度越高,顏色就越深而艷,光譜色的白光成分為0,飽和度達到最高。通常取值范圍為0%~100%,其中0%表示灰色或無色,100%表示純色,通過調整飽和度的值,可以使顏色變得更加鮮艷或者更加灰暗。
明度V:
明度表示顏色明亮的程度,對于光源色,明度值與發光體的光亮度有關;對于物體色,此值和物體的透射比或反射比有關。通常取值范圍為0%(黑)到100%(白),通過調整明度的值,可以使顏色變得更亮或者更暗。
一般對顏色空間的圖像進行有效處理都是在HSV空間進行的,然后對于基本色中對應的HSV分量需要給定一個嚴格的范圍,下面是通過實驗計算的模糊范圍(準確的范圍在網上都沒有給出)。
H: 0— 180
S: 0— 255
V: 0— 255
此處把部分紅色歸為紫色范圍:
為什么有了RGB顏色空間我們還是需要轉換成HSV顏色空間來進行圖像處理呢?
- 符合人類對顏色的感知方式:人類對顏色的感知是基于色調、飽和度和亮度三個維度的,而HSV顏色空間恰好就是通過這三個維度來描述顏色的。因此,使用HSV空間處理圖像可以更直觀地調整顏色和進行色彩平衡等操作,更符合人類的感知習慣。
- 顏色調整更加直觀:在HSV顏色空間中,色調、飽和度和亮度的調整都是直觀的,而在RGB顏色空間中調整顏色不那么直觀。例如,在RGB空間中要調整紅色系的顏色,需要同時調整R、G、B三個通道的數值,而在HSV空間中只需要調整色調和飽和度即可。
- 降維處理有利于計算:在圖像處理中,降維處理可以減少計算的復雜性和計算量。HSV顏色空間相對于RGB顏色空間,減少了兩個維度(紅、綠、藍),這有利于進行一些計算和處理任務,比如色彩分割、匹配等。
因此,在進行圖片顏色識別時,我們會將RGB圖像轉換到HSV顏色空間,然后根據顏色區間來識別目標顏色。
5.圖像轉換(cvtColor())
cv2.cvtColor
是OpenCV中的一個函數,用于圖像顏色空間的轉換。可以將一個圖像從一個顏色空間轉換為另一個顏色空間,比如從RGB到灰度圖,或者從RGB到HSV的轉換等。
cv2.cvtColor(img,code)
img
:輸入圖像,可以是一個Numpy數組繪著一個OpenCV的Mat對象Mat
是一個核心的數據結構,主要用于存儲圖像和矩陣數據。在 Python 中使用 OpenCV 時,通常直接處理的是 NumPy 數組,cv2
模塊自動將Mat
對象轉換為 NumPy 數組。二者之間的轉換是透明且自動完成的。例如,當你使用cv2.imread()
函數讀取圖像時,返回的是一個 NumPy 數組,但在C++中則是Mat
對象。
code
:指定轉換的類型,可以使用預定義的轉換代碼。- 例如
cv2.COLOR_RGB2GRAY
表示從rgb到灰度圖像的轉換。
- 例如
代碼示例:
import cv2 as cv
#讀取圖像
img = cv.imread("../images/1.jpg")
#顏色轉換 cv.cvtColor(img,code)code這里表示轉化模式
#BGR to GRAY
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#BGR to HSV
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
#BGR to RGB
rgb = cv.cvtColor(img,cv.COLOR_BGR2RGB)
cv.imshow("gray",gray)
cv.imshow("hsv",hsv)
cv.imshow("rgb",rgb)
cv.waitKey(0)
cv.destroyAllWindows()
二、灰度實驗
將彩色圖像轉換為灰度圖像的過程稱為灰度化,這種做法在圖像處理和計算機視覺領域非常常見。
灰度圖與彩色圖最大的不同就是:彩色圖是由R、G、B三個通道組成,而灰度圖只有一個通道,也稱為單通道圖像,所以彩色圖轉成灰度圖的過程本質上就是將R、G、B三通道合并成一個通道的過程。本實驗中一共介紹了三種合并方法,分別是最大值法、平均值法以及加權均值法。
1.灰度圖
每個像素只有一個采樣顏色的圖像,這類圖像通常顯示為從最暗黑色到最亮的白色的灰度,盡管理論上這個采樣可以任何顏色的不同深淺,甚至可以是不同亮度上的不同顏色。灰度圖像與黑白圖像不同,在計算機圖像領域中黑白圖像只有黑色與白色兩種顏色;但是,灰度圖像在黑色與白色之間還有許多級的顏色深度。灰度圖像經常是在單個電磁波頻譜如可見光內測量每個像素的亮度得到的,用于顯示的灰度圖像通常用每個采樣像素8位的非線性尺度來保存,這樣可以有256級灰度。
import cv2 as cv
#讀取圖像
img = cv.imread("../images/1.jpg")
#顏色轉換 cv.cvtColor(img,code)
#BGR to GRAY
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
print(gray.shape) #shape:(h,w)
在上述代碼中將一張BGR圖像轉為灰度圖查看他的維度,發現這是一張二維圖像,原本的三通道(一維數組)轉換為一個零維常量(指8位非線性尺寸0~255)
儲存在二維數組中
2.圖像灰度化(最大值法)
實現對彩色圖像的灰度化有三種方式,其中最大值法對于彩色圖像的每個像素,它會從R、G、B三個通道的值中選出最大的一個,并將其作為灰度圖像中對應位置的像素值。
代碼如下(示例):
import cv2 as cv
import numpy as np
#讀取圖像
src = cv.imread("../images/lvbo3.png")
#創建一個新的圖像,用于保存結果
img = np.zeros((src.shape[0],src.shape[1]),dtype=src.dtype)
#循環遍歷圖像的每一個像素
for i in range(src.shape[0]):for j in range(src.shape[1]):# #修改像素值img[i,j]=max(src[i,j,0],src[i,j,1],src[i,j,2])
cv.imshow("result",img)
cv.waitKey(0)
cv.destroyAllWindows()
3.圖像灰度化(平均值法)
對于彩色圖像的每個像素,它會將R、G、B三個通道的像素值全部加起來,然后再除以三,得到的平均值就是灰度圖像中對應位置的像素值。
代碼如下(示例):
import cv2 as cv
import numpy as np
#讀取圖像
src = cv.imread("../images/lvbo3.png")
#創建一個新的圖像,用于保存結果
img = np.zeros((src.shape[0],src.shape[1]),dtype=src.dtype)
#循環遍歷圖像的每一個像素
for i in range(src.shape[0]):for j in range(src.shape[1]):#轉為更大的數據類型,防止溢出img[i,j]=(int(src[i,j,0])+int(src[i,j,1])+int(src[i,j,2]))//3
cv.imshow("result",img)
cv.waitKey(0)
cv.destroyAllWindows()
4.圖像灰度化(加權平均值法)
對于彩色圖像的每個像素,它會按照一定的權重去乘以每個通道的像素值,并將其相加,得到最后的值就是灰度圖像中對應位置的像素值。本實驗中,權重的比例為: R乘以0.299,G乘以0.587,B乘以0.114
,這是經過大量實驗得到的一個權重比例,也是一個比較常用的權重比例(在上面講到對圖像顏色空間轉換的cvtColor函數cv.COLOR_BGR2GRAY實現的圖像灰度化比例一致
)。
所使用的權重之和應該等于1。這是為了確保生成的灰度圖像素值保持在合理的亮度范圍內,并且不會因為權重的比例不當導致整體過亮或過暗。
代碼如下(示例):
import cv2 as cv
import numpy as np
#讀取圖像
src = cv.imread("../images/lvbo3.png")
#創建一個新的圖像,用于保存結果
img = np.zeros((src.shape[0],src.shape[1]),dtype=src.dtype)
#定義權重
wb,wg,wr = 0.114,0.587,0.299
#循環遍歷圖像的每一個像素
for i in range(src.shape[0]):for j in range(src.shape[1]):img[i,j] = round(wb*src[i,j,0]+wg*src[i,j,1]+wr*src[i,j,2])
cv.imshow("result",img)
cv.waitKey(0)
cv.destroyAllWindows()
三、圖像二值化
圖像二值化處理:將某張圖像的所有像素改成只有兩種值之一
。
一幅二值圖像的二維矩陣僅由0、1兩個值構成,“0”代表黑色,“1”代白色。由于每一像素(矩陣中每一元素)取值僅有0、1兩種可能,所以計算機中二值圖像的數據類型通常為1個二進制位。二值圖像通常用于文字、線條圖的掃描識別(OCR)和掩膜圖像的存儲。
其操作的圖像也必須是灰度圖
。也就是說,二值化的過程,就是將一張灰度圖上的像素根據某種規則修改為0和maxval(maxval表示最大值,一般為255,顯示白色)兩種像素值,使圖像呈現黑白的效果,能夠幫助我們更好地分析圖像中的形狀、邊緣和輪廓等特征。
- 簡便:降低計算量和計算需求,加快處理速度。
- 節約資源:二值圖像占用空間遠小于彩色圖。
- 邊緣檢測:二值化常作為邊緣檢測的預處理步驟,因為簡化后的圖易于識別出輪廓和邊界。
1.閾值法(THRESH_BINARY)和反閾值法(THRESH_BINARY_INV)
全局閾值法:
_,binary = cv2.threshold(img,thresh,maxval,type)
img
:輸入圖像,要進行二值化處理的灰度圖。thresh
:設定的閾值。當像素值大于(或小于,取決于閾值類型)thresh
時,該像素被賦予的值。type
:閾值處理的類型。- 返回值:
- 第一個值(通常用下劃線表示):計算出的閾值,若使用自適應閾值法,會根據算法自動計算出這個值。
- 第二個值(binary):二值化后的圖像矩陣。與輸入圖像尺寸相同。
代碼如下(示例):
import cv2 as cv
#讀取圖像
flower = cv.imread('../images/flower.png')
#灰度處理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))#二值化處理 閾值法(大于閾值為maxval,小于閾值為0)
_, binary = cv.threshold(gray,200,255,cv.THRESH_BINARY)
cv.imshow("binary",binary)#二值化處理 反閾值法(大于閾值的為0,小于閾值為maxval)
_, inv = cv.threshold(gray,200,255,cv.THRESH_BINARY_INV)
cv.imshow("inv",inv)
cv.waitKey(0)
cv.destroyAllWindows()
運行結果:
2.截斷閾值法(THRESH_TRUNC)
截斷閾值法,指將灰度圖中的所有像素與閾值進行比較,像素值大于閾值的部分將會被修改為閾值,小于等于閾值的部分不變(當閾值為255時二值化處理的灰度圖與原灰度圖沒有區別
)。
換句話說,經過截斷閾值法處理過的二值化圖中的最大像素值就是閾值。
代碼如下(示例):
import cv2 as cv
#讀取圖像
flower = cv.imread('../images/flower.png')
#灰度處理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))
#截斷閾值法(大于閾值等于閾值,小于閾值不變)
_, trunc = cv.threshold(gray,200,0,cv.THRESH_TRUNC)
cv.imshow("trunc",trunc)
cv.waitKey(0)
cv.destroyAllWindows()
使用截斷閾值法進行圖像二值化處理時,設置的maxval
參數實際上是不起作用的(如圖):
3.低閾值零處理(THRESH_TOZERO)與超閾值零處理(THRESH_TOZERO_INV)
- 低閾值零處理,像素值小于等于閾值的部分被置為0(黑色),像素值大于閾值部分不變。
- 超閾值零處理,像素值大于閾值的部分置為0(黑色),像素值小于等于閾值的部分不變。
代碼如下(示例):
import cv2 as cv
#讀取圖像
flower = cv.imread('../images/flower.png')
#灰度處理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))
#低閾值零處理(低于閾值為0,高于閾值不變)
_, tozero = cv.threshold(gray,127,0,cv.THRESH_TOZERO)
cv.imshow("tozero",tozero)
#超閾值零處理(高于閾值為0,低于閾值不變)
_, tozero_inv = cv.threshold(gray,127,0,cv.THRESH_TOZERO_INV)
cv.imshow("tozero_inv",tozero_inv)
cv.waitKey(0)
cv.destroyAllWindows()
運行結果如下:
4.OTSU閾值法(threshold())
cv2.THRESH_OTS 并不是一個有效的閾值類型或標。THRESH_OTSU
本身并不是一個獨立的閾值化方法,而是與 OpenCV 中的二值化方法結合使用的一個標志。具體來說,THRESH_OTSU
通常與 THRESH_BINARY
或 THRESH_BINARY_INV
結合使用。在實際應用中,如果你使用 THRESH_OTSU
標志但沒有指定其他二值化類型,默認情況下它會與 THRESH_BINARY
結合使用。也就是說,當你僅指定了 cv2.THRESH_OTSU
,實際上等同于同時指定了 cv2.THRESH_BINARY + cv2.THRESH_OTSU
。
代碼如下(示例):
import cv2 as cv
#讀取圖像
flower = cv.imread('../images/flower.png')
#灰度處理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))#OTSU閾值法(thresh)由函數計算得到,默認結合閾值法
_,otsu = cv.threshold(gray,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
cv.imshow("otsu",otsu)
#OTSU結合反閾值法
_,otsu_inv = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU)
cv.imshow("otsu_inv",otsu_inv)
cv.waitKey(0)
cv.destroyAllWindows()
運行結果:
5.自適應二值化(adaptiveThreshold())
與二值化算法相比,自適應二值化更加適合用在明暗分布不均的圖片,因為圖片的明暗不均,導致圖片上的每一小部分都要使用不同的閾值進行二值化處理,這時候傳統的二值化算法就無法滿足我們的需求了,于是就出現了自適應二值化。
cv2.adaptiveThreshold(image_np_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 7, 10)
其中各個參數的含義如下:
maxval
:最大閾值,一般為255
adaptiveMethod
:小區域閾值的計算方式:
ADAPTIVE_THRESH_MEAN_C
:小區域內取均值
ADAPTIVE_THRESH_GAUSSIAN_C
:小區域內加權求和,權重是個高斯核
thresholdType
:二值化方法,只能使用THRESH_BINARY、THRESH_BINARY_INV,也就是閾值法和反閾值法
blockSize
:選取的小區域的面積,如7就是7*7的小塊。
c
:最終閾值等于小區域計算出的閾值再減去此值
下面介紹一下這兩種方法。
- 取均值法
假如我們使用的小區域是3*3的,那么就會從圖片的左上角開始(也就是像素值為162的地方)計算其鄰域內的平均值,如果處于邊緣地區就會對邊界進行填充,填充值就是邊界的像素點,如下圖所示:
代碼如下(示例):
import cv2 as cv
#讀取圖像
flower = cv.imread('../images/flower.png')
#灰度處理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))
#均值法
mean = cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,11,2)
cv.imshow("mean",mean)
cv.waitKey(0)
cv.destroyAllWindows()
- 高斯核加權均值法
對小區域內的像素進行加權求和得到新的閾值,其權重值來自于高斯分布。
高斯分布,通過概率密度函數來定義高斯分布,一維高斯概率分布函數為:
p(y)=1σ2πe?(y?μ)22σ2p(y)={\frac{1}{\sigma{\sqrt{2\pi}}}}e^{{\frac{-(y-\mu)^{2}}{2\sigma^{2}}}} p(y)=σ2π?1?e2σ2?(y?μ)2?
我們拓展到二維圖像,一般情況下我們使x軸和y軸的相等并且,此時我們可以得到二維高斯函數的表達式為:
g(x,y)=12πσ2e?(x2+y2)2σ2g(x,y)=\frac{1}{2\pi\sigma ^{2}}e^{-\frac{(x^{2}+y^{2})}{2\sigma^{2}}} g(x,y)=2πσ21?e?2σ2(x2+y2)?
高斯概率函數是相對于二維坐標產生的,其中(x,y)為點坐標,要得到一個高斯濾波器模板,應先對高斯函數進行離散化,將得到的值作為模板的系數。例如:要產生一個3*3的高斯權重核,以核的中心位置為坐標原點進行取樣,其周圍的坐標如下圖所示(x軸水平向右,y軸豎直向上)
通過這個高斯核,即可對圖片中的每個像素去計算其閾值,并將該閾值減去固定值得到最終閾值,然后根據二值化規則進行二值化。
代碼如下(示例):
import cv2 as cv
#讀取圖像
flower = cv.imread('../images/flower.png')
#灰度處理
gray = cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray = cv.resize(gray,(400,400))
#自適應二值化(高斯核加權法)
gauss = cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,2)
cv.imshow("gauss",gauss)
cv.waitKey(0)
cv.destroyAllWindows()
兩種方法執行對比:
上述兩種方法,僅僅只是卷積核的參數會發生變化,計算過程是一樣的,很明顯高斯加權均值法的二值化細致程度要高一些。
四、圖像鏡像翻轉與仿射變換
-
仿射變換的基本原理
-
線性變換
-
二維空間中,圖像點坐標為(x,y)(x,y)(x,y),仿射變換的目標是將這些點映射到新的位置 (x′,y′)(x', y')(x′,y′)。
-
為了實現這種映射,通常會使用一個矩陣乘法的形式:
(類似于y=kx+b)
a,b,c,d 是線性變換部分的系數,控制旋轉、縮放和剪切。
-
t_x,t_y 是平移部分的系數,控制圖像在平面上的移動。
-
輸入點的坐標被擴展為齊次坐標形式[x,y,1][x,y,1][x,y,1],以便能夠同時處理線性變換和平移
-
-
-
cv2.warpAffine()函數
仿射變換函數
cv2.warpAffine(img,M,dsize)
-
img:輸入圖像。
-
M:2x3的變換矩陣,類型為
np.float32
。 -
dsize:輸出圖像的尺寸,形式為
(width,height)
。
1.圖像翻轉(圖像鏡像旋轉)
在OpenCV中,圖片的鏡像旋轉是以圖像的中心為原點進行鏡像翻轉的。
-
cv2.flip(img,flipcode)
-
參數
- img: 要翻轉的圖像
- flipcode: 指定翻轉類型的標志
- flipcode=0: 垂直翻轉,圖片像素點沿x軸翻轉
- flipcode>0: 水平翻轉,圖片像素點沿y軸翻轉
- flipcode<0: 水平垂直翻轉,水平翻轉和垂直翻轉的結合
代碼如下(示例):
import cv2 as cv
import numpy as np
#讀取圖像
cao = cv.imread("../images/cao.png")
cao=cv.resize(cao,(300,300))
#翻轉,鏡像翻轉,以圖像原點為中心(cv.flip(img,flipcode))
#0(垂直翻轉沿X軸)>0(水平翻轉沿Y軸)<0(垂直水平翻轉)
flip_0 = cv.flip(cao,0)
flip_1 = cv.flip(cao,1)
flip_2 = cv.flip(cao,-1)
cv.imshow("cao",cao)
cv.imshow("flip_0",flip_0)
cv.imshow("flip_1",flip_1)
cv.imshow("flip_2",flip_2)
cv.waitKey(0)
cv.destroyAllWindows()
執行效果:
2.圖像旋轉
cv2.getRotationMatrix2D()函數
獲取旋轉矩陣
cv2.getRotationMatrix2D(center,angle,scale)
- center:旋轉中心點的坐標,格式為
(x,y)
。 - angle:旋轉角度,單位為度,正值表示逆時針旋轉負值表示順時針旋轉。
- scale:縮放比例,若設為1,則不縮放。
- 返回值:M,2x3的旋轉矩陣。
代碼示例:
import cv2 as cv
#讀取圖像
img = cv.imread("../images/1.jpg")
cv.imshow("img",img)
#獲取旋轉矩陣cv2.getRotationMatrix2D(旋轉中心,旋轉角度,縮放比例)
M = cv.getRotationMatrix2D((img.shape[1]/2,img.shape[0]/2),45,1)
#仿射變換cv2.warpAffine(src, M, (width, height))
dst = cv.warpAffine(img,M,(img.shape[1],img.shape[0]))
cv.imshow("src",dst)
cv.waitKey(0)
cv.destroyAllWindows()
執行效果:
3.圖像平移
移操作可以將圖像中的每個點沿著某個方向移動一定的距離。
假設我們有一個點 P(x,y)P(x,y)P(x,y),希望將其沿x軸方向平移txt_xtx?*個單位,沿y軸方向平移tyt_yty?個單位到新的位置P′(x′,y′)P′(x′,y′)P′(x′,y′),那么平移公式如下:
? x′=x+txx′=x+txx′=x+tx
? y′=y+tyy′=y+tyy′=y+ty
在矩陣形式下,該變換可以表示為:
代碼示例:
import cv2 as cv
import numpy as np
#讀取圖像
img = cv.imread("../images/1.jpg")
img = cv.resize(img,(300,300))
#創建一個平移矩陣
M = np.float32([[1,0,100],[0,1,50]])
#仿射變換
dst = cv.warpAffine(img,M,(img.shape[1]*2,img.shape[0]*2))
cv.imshow("img",img)
cv.imshow("src",dst)
cv.waitKey(0)
cv.destroyAllWindows()
運行效果:
4.圖像縮放
縮放操作可以改變圖片的大小。
-
假設要把圖像的寬高分別縮放為0.5和0.8,那么對應的縮放因子sx=0.5,sy=0.8。
-
點P(x,y)P(x,y)P(x,y)對應到新的位置P′(x′,y′)P'(x',y')P′(x′,y′),縮放公式為:
x′=sx?xx′=s_x*xx′=sx??x
? y′=sy?yy′=s_y*yy′=sy??y
在矩陣形式下,該變換可以表示為:
-
相較于圖像旋轉中只能等比例的縮放,圖像縮放更加靈活,可以在指定方向上進行縮放。
sx和sy分別表示在x軸和y軸方向上的縮放因子
。
代碼示例:
import cv2 as cv
import numpy as np
#讀取圖像
img = cv.imread("../images/1.jpg")
img = cv.resize(img,(400,400))
#創建一個縮放矩陣
M = np.float32([[0.5,0,100],[0,0.5,100]])
dst = cv.warpAffine(img,M,(img.shape[1],img.shape[0]))
cv.imshow("img",img)
cv.imshow("src",dst)
cv.waitKey(0)
cv.destroyAllWindows()
執行效果:
結語
圖像預處理是計算機視覺任務的“隱形引擎”,合理運用這些技術可以顯著提升模型的性能和魯棒性。本文從 顏色空間轉換 到 仿射變換,系統介紹了 OpenCV 的核心預處理方法,并提供了可復現的代碼示例。
📌 動手挑戰: 嘗試對一張傾斜的名片圖片進行仿射變換矯正,并利用二值化提取清晰的文字信息!
🔗 后續預告: 在下一篇文章中,我們將深入探討 圖像濾波與邊緣檢測,進一步解鎖 OpenCV 的高級功能!