目錄
一、圖像翻轉(鏡像翻轉)
1. 定義
2. OpenCV 函數
3. 數學表達
二、圖像仿射變換
1. 定義
?2. 仿射變換的基本原理
3. OpenCV 函數
4. 圖像旋轉
5. 圖像平移
6. 圖像縮放
7. 圖像剪切
8. 為什么會出現黑色背景?
三、圖像色彩空間轉換
1. 定義
2.?RGB顏色空間
3. 顏色加法
4. 顏色加權加法
5. HSV顏色空間
6.?RGB轉Gray(灰度)
7.?RGB轉HSV
?8. 綜合案例
8.1顏色加法:
?8.2 顏色轉換:
四、灰度實驗
1. 灰度圖
2. 最大值法
3. 平均值法
4. 加權均值法
?5. 兩個極端的灰度值
一、圖像翻轉(鏡像翻轉)
1. 定義
圖像翻轉是對圖像在某一軸(水平、垂直或對角)上的鏡像操作。
2. OpenCV 函數
cv2.flip(src, flipCode)
-
flipCode
:-
0
:上下翻轉(垂直鏡像),垂直翻轉,圖片像素點沿x軸翻轉 -
1
:左右翻轉(水平鏡像),水平翻轉,圖片像素點沿y軸翻轉 -
-1
:上下左右同時翻轉,水平垂直翻轉,水平翻轉和垂直翻轉的結合
-
案例演示:
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
pig = cv.resize(pig,(500,500))
#鏡像翻轉
#垂直翻轉
flip = cv.flip(pig,0)
cv.imshow('flip', flip)
#水平翻轉
flip1 = cv.flip(pig,1)
cv.imshow('flip1', flip1)
#水平垂直翻轉flip2 = cv.flip(pig,-1)
cv.imshow('flip2', flip2)cv.waitKey(0)
cv.destroyAllWindows()
原圖:
?
?水平翻轉--filp:
垂直翻轉--filp1:
水平垂直翻轉--filp2:
3. 數學表達
圖像為矩陣 I(x,y)I(x, y)I(x,y),假設寬度為 WWW,高度為 HHH,翻轉后坐標變換為:
-
水平翻轉:
-
垂直翻轉:
二、圖像仿射變換
1. 定義
仿射變換是保線性、保平行的二維變換,包括:平移、旋轉、縮放、剪切、翻轉等。
仿射變換的基本性質
保持直線
保持平行
比例不變性
不保持角度和長度
常見的仿射變換類型
旋轉:繞著某個點或軸旋轉一定角度。
平移:僅改變物體的位置,不改變其形狀和大小。
縮放:改變物體的大小。
剪切:使物體發生傾斜變形。
?2. 仿射變換的基本原理
線性變換
二維空間中,圖像點坐標為$$(x,y)$$,仿射變換的目標是將這些點映射到新的位置 $$(x', y')$$。
為了實現這種映射,通常會使用一個矩陣乘法的形式:(類似于y=kx+b)
二維仿射變換的通用公式如下:
也可寫成擴展的 2×3 矩陣形式:
(x,y):原始坐標
(x′,y′):變換后的新坐標
a,b,c,d:旋轉、縮放、剪切控制項
e,f:平移量
變換 | 變換矩陣形式 |
---|---|
平移 | |
縮放 | |
旋轉 | |
剪切 | |
3. OpenCV 函數
?獲得仿射矩陣
cv2.warpAffine(img,M,dsize)
-
img:輸入圖像。
-
M:2x3的變換矩陣,類型為
np.float32
。 -
dsize:輸出圖像的尺寸,形式為
(width,height)
。
4. 圖像旋轉
旋轉圖像可以將圖像繞著某個點旋轉一定的角度。
cv2.getRotationMatrix2D()函數
-
獲取旋轉矩陣
cv2.getRotationMatrix2D(center,angle,scale)
-
center:旋轉中心點的坐標,格式為
(x,y)
。 -
angle:旋轉角度,單位為度,正值表示逆時針旋轉負值表示順時針旋轉。
-
scale:縮放比例,若設為1,則不縮放。
-
返回值:M,2x3的旋轉矩陣。
-
案例:
import cv2 as cv
import numpy as np
flower = cv.imread("D:\OpenCV_notes\day02\images\\flower.png")
flower = cv.resize(flower,(360,360))
#獲取旋轉矩陣 cv2.getRotationMatrix2D(center,angle,scale) 2*3
M=cv.getRotationMatrix2D((180,180),-45,1)#仿射變換函數 cv2.warpAffine(src,M,(cols,rows))
rotate = cv.warpAffine(flower,M,(flower.shape[1],flower.shape[0]))
cv.imshow('rotate',rotate)cv.waitKey(0)
cv.destroyAllWindows()
原圖:
圖像旋轉后--rotate:
5. 圖像平移
平移操作可以將圖像中的每個點沿著某個方向移動一定的距離。
-
假設我們有一個點 $P(x,y)$,希望將其沿x軸方向平移$t_x$*個單位,沿y軸方向平移$t_y$個單位到新的位置$P′(x′,y′)$,那么平移公式如下:
$x′=x+tx$
$y′=y+ty$
-
在矩陣形式下,該變換可以表示為
- 這里的$t_x$和$t_y$分別代表在x軸和y軸上的平移量。
案例:
import cv2 as cv
import numpy as np
flower = cv.imread("D:\OpenCV_notes\day02\images\\flower.png")
flower = cv.resize(flower,(360,360))
#定義平移量
tx,ty=100,100#定義平移矩陣
M=np.float32([[1,0,tx],[0,1,ty]])#仿射變換函數 cv2.warpAffine(src,M,(cols,rows))
translate = cv.warpAffine(flower,M,(flower.shape[1],flower.shape[0]))
cv.imshow("translate",translate)
cv.imshow("flower",flower)cv.waitKey(0)
cv.destroyAllWindows()
?原圖:
圖像平移后--translate:
6. 圖像縮放
縮放操作可以改變圖片的大小。
-
假設要把圖像的寬高分別縮放為0.5和0.8,那么對應的縮放因子sx=0.5,sy=0.8。
-
點$P(x,y)$對應到新的位置$P'(x',y')$,縮放公式為:
$x′=s_x*x$
$y′=s_y*y$
-
在矩陣形式下,該變換可以表示為:
sx和sy分別表示在x軸和y軸方向上的縮放因子。 ?
相較于圖像旋轉中只能等比例的縮放,圖像縮放更加靈活,可以在指定方向上進行縮放。 ?
案例:?
import cv2 as cv
import numpy as np
flower = cv.imread("D:\OpenCV_notes\day02\images\\flower.png")
flower = cv.resize(flower,(360,360))
#定義縮放因子
sx,sy=0.5,0.5
#定義縮放矩陣
M = np.float32([[sx,0,0],[0,sy,0]])
#仿射變化
dst = cv.warpAffine(flower,M,(flower.shape[1],flower.shape[0]))
cv.imshow("src",flower)
cv.imshow("dst",dst)cv.waitKey(0)
cv.destroyAllWindows()
原圖:
?
圖像縮放后--dst:
7. 圖像剪切
剪切操作可以改變圖形的形狀,以便其在某個方向上傾斜,它將對象的形狀改變為斜邊平行四邊形,而不改變其面積。
-
想象我們手上有一張矩形紙片,如果你固定紙片的一邊,并沿著另一邊施加一個平行于該邊的力,這張紙片就會變形為一個平行四邊形。這就是剪切變換的一個直觀解釋。
-
對于二維空間中的點$P(x,y)$,對他進行剪切變換:
沿x軸剪切:$x'=x+sh_y*y$ $y'=y$
沿y軸剪切:$x'=x$ $y'=sh_x*x+y$
-
當需要同時沿兩個方向進行剪切時,$x'=x+sh_yy$ , $y'=sh_xx+y$
-
在矩陣形式下,該變換可以表示為:
圖示理解:
shy和shx分別對應沿x軸和y軸方向上的剪切因子。
-
可以理解為,x不變,y偏移 ?
案例:
import cv2 as cv
import numpy as np
flower = cv.imread("D:\OpenCV_notes\day02\images\\flower.png")
flower = cv.resize(flower,(360,360))
#設置剪切因子
shx = 0.3
shy = 0.3
#設置剪切矩陣
M = np.float32([[shx * flower.shape[1], 0, 1],[0, shy * flower.shape[1], 1]])
#仿射變化
dst = cv.warpAffine(flower,M,(flower.shape[1],flower.shape[0]))
cv.imshow("src",flower)
cv.imshow("dst",dst)cv.waitKey(0)
cv.destroyAllWindows()
?原圖:
圖像剪切后:
?
8. 為什么會出現黑色背景?
原因:坐標映射存在空洞
仿射變換是將原圖的每個像素位置映射到一個新的位置:
變換后的圖像通常會:
-
改變方向(旋轉)
-
改變大小(縮放)
-
改變位置(平移)
-
改變形狀(剪切)
導致部分輸出圖像的像素位置 在原圖中沒有對應的像素值,這類區域系統會使用默認值填充。
OpenCV 默認的行為:
在 cv2.warpAffine()
中,如果變換后的圖像某些區域無法從源圖像映射到像素值,則默認用黑色填充:
dst = cv2.warpAffine(src, M, (width, height))
沒有設置其他參數時,空洞區域填充為黑色,即
(0, 0, 0)
(彩色)或0
(灰度)。
三、圖像色彩空間轉換
1. 定義
OpenCV中,圖像色彩空間轉換是一個非常基礎且重要的操作,就是將圖像從一種顏色表示形式轉換為另一種表示形式的過程。通過將圖像從一個色彩空間轉換到另一個色彩空間,可以更好地進行特定類型的圖像處理和分析任務。常見的顏色空間包括RGB、HSV、YUV等。
-
色彩空間轉換的作用
-
提高圖像處理效果
-
節省計算資源
-
2.?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)的原因。
3. 顏色加法
你可以使用OpenCV的cv.add()函數把兩幅圖像相加,或者可以簡單地通過numpy操作添加兩個圖像,如res = img1 + img2。兩個圖像應該具有相同的大小和類型。
OpenCV加法和Numpy加法之間存在差異。OpenCV的加法是飽和操作,而Numpy添加是模運算。
4. 顏色加權加法
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 + γ
這里γ取為零。
5. 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顏色空間,然后根據顏色區間來識別目標顏色。
6.?RGB轉Gray(灰度)
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到灰度圖像的轉換。
-
-
7.?RGB轉HSV
在圖像處理中,HSV(Hue 色相、Saturation 飽和度、Value 亮度)是一種更接近人類感知的色彩表示方式。相較于 RGB,HSV 更適合用于顏色分割、目標檢測等任務。
OpenCV 提供了函數 cv2.cvtColor()
進行顏色空間轉換。
hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
-
img:輸入圖像(RGB 格式),通常是 NumPy 數組
-
code:轉換類型(此處為
cv2.COLOR_RGB2HSV
)?
注意:如果你用的是 cv2.imread()
讀取圖像,那么默認圖像是 BGR 格式,此時應使用:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
?8. 綜合案例
8.1顏色加法:
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
cao = cv.imread("D:\OpenCV_notes\day02\images\cao.png")
#飽和操作 cvv.add(src1,src2) np.unit8 0~255 250+10
dst1 = cv.add(pig,cao)
cv.imshow("dst1",dst1)
#numpy直接相加 取模運算 對256取模 250+10=260 260%256=4
dst2 = pig + cao
cv.imshow("dst2",dst2)
#舉個例子
x = np.uint8([[250]])
y = np.uint8([[10]])
xy1 = cv.add(x, y) # 飽和加法,結果為 255
xy2 = x + y
print(xy1)
print(xy2)
#顏色加權加法 cv.addWeighted(img1,alpha,img2,beta,gamma)
dst3 = cv.addWeighted(pig,0.7,cao,0.3,2)
cv.imshow("dst3",dst3)cv.waitKey(0)
cv.destroyAllWindows()
原圖:
pig:
cao:
?
?飽和操作后--dst1:
?直接相加,取模運算--dst2:
顏色加權加法后--dst3:
?8.2 顏色轉換:
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
#顏色轉換 cvv.cvtColor(src,code[,dst[,alpha[,beta]]])
#轉灰度圖
gray = cv.cvtColor(pig, cv.COLOR_BGR2GRAY)
cv.imshow("gray", gray)
#轉HSV
hsv = cv.cvtColor(pig, cv.COLOR_BGR2HSV)
cv.imshow("hsv", hsv)
#轉rgb
rgb = cv.cvtColor(pig, cv.COLOR_BGR2RGB)
cv.imshow("rgb", rgb)cv.waitKey(0)
cv.destroyAllWindows()
原圖:
轉灰度圖后--gray:
轉HSV后--HSV :
轉rgb后--rgb:
四、灰度實驗
1. 灰度圖
每個像素只有一個采樣顏色的圖像,這類圖像通常顯示為從最暗黑色到最亮的白色的灰度,盡管理論上這個采樣可以任何顏色的不同深淺,甚至可以是不同亮度上的不同顏色。灰度圖像與黑白圖像不同,在計算機圖像領域中黑白圖像只有黑色與白色兩種顏色;但是,灰度圖像在黑色與白色之間還有許多級的顏色深度。灰度圖像經常是在單個電磁波頻譜如可見光內測量每個像素的亮度得到的,用于顯示的灰度圖像通常用每個采樣像素8位的非線性尺度來保存,這樣可以有256級灰度。
2. 最大值法
對于彩色圖像的每個像素,它會從R、G、B三個通道的值中選出最大的一個,并將其作為灰度圖像中對應位置的像素值。
例如某圖像中某像素點的像素值如上圖所示,那么在使用最大值法進行灰度化時,就會從該像素點對應的RGB通道中選取最大的像素值作為灰度值,所以在灰度圖中的對應位置上,該像素點的像素值就是121。 ?
案例:?
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
shape = pig.shape
pig1 = np.zeros(shape, dtype=np.uint8)#創建一個全零的圖片
#循環遍歷 每一行
for i in range(shape[0]):#循環遍歷每一列for j in range(shape[1]):pig1[i,j] = max(pig[i,j,0],pig[i,j,1],pig[i,j,2])cv.imshow('pig1', pig1)
cv.waitKey(0)
cv.destroyAllWindows()
原圖:
最大值法后--pig1:?
3. 平均值法
對于彩色圖像的每個像素,它會將R、G、B三個通道的像素值全部加起來,然后再除以三,得到的平均值就是灰度圖像中對應位置的像素值
?例如某圖像中某像素點的像素值如上圖所示,那么在使用平均值進行灰度化時,其計算結果就是(91+121+46)/3=86(對結果進行取整),所以在灰度圖中的對應位置上,該像素點的像素值就是86。
案例:
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
shape = pig.shape
pig1 = np.zeros(shape, dtype=np.uint8)#創建一個全零的圖片
#循環遍歷 每一行
for i in range(shape[0]):#循環遍歷每一列for j in range(shape[1]):pig1[i,j] = (int(pig[i,j,0])+int(pig[i,j,1])+int(pig[i,j,2]))//3
cv.imshow('pig1', pig1)cv.waitKey(0)
cv.destroyAllWindows()
平均值法后--pig1:
4. 加權均值法
對于彩色圖像的每個像素,它會按照一定的權重去乘以每個通道的像素值,并將其相加,得到最后的值就是灰度圖像中對應位置的像素值。本實驗中,權重的比例為: R乘以0.299,G乘以0.587,B乘以0.114,這是經過大量實驗得到的一個權重比例,也是一個比較常用的權重比例。
所使用的權重之和應該等于1。這是為了確保生成的灰度圖像素值保持在合理的亮度范圍內,并且不會因為權重的比例不當導致整體過亮或過暗。
?例如某圖像中某像素點的像素值如上圖所示,那么在使用加權平均值進行灰度化時,其計算結果就是10*0.299+121*0.587+46*0.114=79。所以在灰度圖中的對應位置上,該像素點的像素值就是79。這種是最常用的加權均值方式(cv2內置了)
案例:
import cv2 as cv
import numpy as np
pig = cv.imread("D:\OpenCV_notes\day02\images\pig.png")
shape = pig.shape
pig1 = np.zeros(shape, dtype=np.uint8)#創建一個全零的圖片
#定義權重
wb,wg,wr = 0.3,0.59,0.11
#循環遍歷 每一行
for i in range(shape[0]):#循環遍歷每一列for j in range(shape[1]):pig1[i,j] = round(wb*pig[i,j,0]+wg*pig[i,j,1]+wr*pig[i,j,2])cv.imshow('pig1', pig1)
cv.waitKey(0)
cv.destroyAllWindows()
加權平均值法后--pig1:
?
?5. 兩個極端的灰度值
在灰度圖像中,“極端”的灰度值指的是亮度的兩個極端:最暗和最亮的值。
- **最暗的灰度值**:0。這代表完全黑色,在灰度圖像中沒有任何亮度。
- **最亮的灰度值**:255。這代表完全白色,在灰度圖像中具有最大亮度。