- cv2的基本函數
import cv2 # 導入cv2模組
cv2.imread() # 從檔案讀進一個numpy array(陣列)
cv2.IMREAD_GRAYSCALE # 以灰階的方式讀進這個圖片
cv2.imshow() # 用一個視窗顯示圖片的內容
# 這個指令必須在有圖形界面的編輯環境中才能夠使用,pythonanyway就不可以。
# 所以有時候我們必須把array的內容寫到(cv2.imwrite())一個檔案(圖形檔案xxx.png),
# 再使用瀏覽器打開這個圖形檔案,才能夠顯現圖片的內容。
cv2.waitKey(0) # 工作暫停直到從鍵盤敲入任何鍵才繼續執行下面的指令
cv2.destroyAllWindows() # 關閉所有開啟瀏覽圖片的視窗
cv2.destroyWindow() # 關閉某一開啟瀏覽圖片的視窗
cv2.imwrite() # 把array的內容寫到一個檔案(圖形檔案xxx.png)
import numpy as np
import cv2
img = cv2.imread('rect-3.png')
print('type=',type(img))
print('shape=',img.shape,' ndim=',np.ndim(img))
img_gray = cv2.imread('rect-3.png', cv2.IMREAD_GRAYSCALE)
print('shape=',img_gray.shape,' ndim=',np.ndim(img_gray))
cv2.imshow('Image 1', img)
cv2.imshow('Image 2', img_gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
type= class 'numpy.ndarray'
shape= (260, 298, 3) ndim= 3
type= class 'numpy.ndarray'
shape= (260, 298) ndim= 2
|
import cv2
img1 = cv2.imread('rect-3.png', cv2.IMREAD_GRAYSCALE)
cv2.imwrite('rect_gray1.png',img1)
import numpy as np
img2=np.full((img1.shape),128)
print('shape of img1 & img2:',img1.shape,img2.shape)
cv2.imwrite('rect_gray2.png',img2)
|
shape of img1 & img2: (260, 298) (260, 298)
|
- 圖片的縮圖與陣列的關係
圖片是以像素的形式呈現而像素的資訊由陣列所儲存的數據所決定。首先我們先用cv2.imread()將一個圖片檔案(rect-3.png)讀進主程式當中,並且將這些數據指定為一個變數img,然後考察這個變數img的資料型態、內容和大小,這樣就能夠清楚的掌握opencv是如何建立圖片和變數之間的關聯。
img2=np.copy(img)是將一個陣列img複製成另外一個陣列變數img2。接著下面兩個指令是利用切片的方法,將新的陣列img2重新設定某一些元素的數值,其中我們讓綠色和紅色的像素設定為255的最大值。將這兩種顏色混合(綠+紅)將會得到黃色,而根據切片的行列指標可以得到一條水平的黃色線出現在新的圖形檔案之中。關於行列的設定和效果,請再參考下一個單元(直接取代陣列的數值進而可以有目的地改變圖片)中的範例可以促進你的了解。
import numpy as np
import cv2
img=cv2.imread('rect-3.png')
print('type(img)=',type(img))
print('img.shape=',img.shape)
print('type(img[0][0][0])=',type(img[0][0][0]))
cv2.imshow('MY img',img)
img2=np.copy(img)
img2[130:136,:,0:1]=0
img2[130:136,:,1:3]=255
cv2.imwrite('rect-3-hc-YL.png',img2)
cv2.imshow('MY img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
type(img)= class 'numpy.ndarray'
img.shape= (260, 298, 3)
type(img[0][0][0])= class 'numpy.uint8'
|
上面的輸出當中我們注意到陣列的元素資料型態是uint8,這是專門用來儲存圖形檔案陣列的元素的資料型態,其數字是不帶符號的整數,範圍落在[0,255]之間。如果我們把這個整數變數跟其他的整數做算術運算的時候,如果數值會超過255,那麼將會反覆折疊回到[0,255]的區間,我們以下面這個程式為例來說明這個現象。
import numpy as np
import cv2
a=[400,250,25,2000]
print('type(a)=',type(a))
print('a=',a)
print('---use uint8 to convert a list to array---' )
b=np.uint8(a)
print('type(b)=',type(b))
print('type(b[0])=',type(b[0]))
print('b=',b,400-256,2000-7*256)
c=300
d=np.uint8(c)
e=np.uint8(220)
e=e+d
print('type(c)=',type(c),' type(d)=',type(d))
print('c=',c,' d=',d,' e=',300-256,e,44+220-256)
|
type(a)= class 'list'
a= [400, 250, 25, 2000]
---use uint8 to convert a list to array---
type(b)= class 'numpy.ndarray'
type(b[0])= class 'numpy.uint8'
b= [144 250 25 208] 144 208
cv_uint8.py:14: RuntimeWarning: overflow encountered in ubyte_scalars
e=e+d
type(c)= class 'int' type(d)= class 'numpy.uint8'
c= 300 d= 44 e= 44 8 8
|
圖片的縮圖
圖片是以像素的形式呈現而像素的資訊由陣列所儲存的數據所決定。將圖片縮圖等同於將一個比較多的資訊的大的陣列指,指按照比例保留部分的陣列數據,因此縮圖與陣列之間是有對應關係的。
import numpy as np
import cv2
img = cv2.imread('rect-3.png')
(Lx,Ly)=(img.shape[0],img.shape[1])
F=4
Lx2=int(Lx/F); Ly2=int(Ly/F)
img2=np.full((Lx2,Ly2,3),0,dtype=np.uint8)
print('Lx=',Lx,' Ly=',Ly,' Lx2=',Lx2,' Ly2=',Ly2)
for i in range(0,Lx2):
for j in range(0,Ly2):
x=i*F; y=j*F
for k in range(3):
img2[i][j][k]=img[x][y][k]
print(img.shape)
print(img2.shape)
cv2.imwrite('rect-3F4.png', img2)
cv2.imshow('My Image 1', img)
cv2.imshow('My Image 2', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
Lx= 260 Ly= 298 Lx2= 65 Ly2= 74
(260, 298, 3)
(65, 74, 3)
|
- 直接取代陣列的數值進而可以有目的地改變圖片
用雙重迴圈直接將陣列的數值,以黃色所對應的數值取代(B,G,R)=(0.255,255),就可將圖片某個區塊的顏色完全取代為黃色,達到遮蔽的效應。
import numpy as np
import cv2
img = cv2.imread('rect-3.png')
(Lx,Ly)=(img.shape[0],img.shape[1])
F=2
Lx2=int(Lx/F); Ly2=int(Ly/F)
img2=np.copy(img)
print('Lx=',Lx,' Ly=',Ly,' Lx2=',Lx2,' Ly2=',Ly2)
for i in range(0,Lx2):
for j in range(0,Ly2):
for k in range(3):
img2[i][j][0]=0;img2[i][j][1]=255;img2[i][j][2]=255;
print(img.shape)
print(img2.shape)
cv2.imwrite('rect-3block_1.png', img2)
cv2.imshow('My Image 1', img)
cv2.imshow('My Image 2', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
Lx= 260 Ly= 298 Lx2= 130 Ly2= 149
(260, 298, 3)
(260, 298, 3)
|
- 列印陣列的數值
列印陣列的數值內容以便驗證與圖形的對應關係。
import numpy as np
import cv2
img = cv2.imread('rect-3F4.png')
(Lx,Ly)=(img.shape[0],img.shape[1])
Lx2=int(Lx/2)
print('Lx=',Lx,' Ly=',Ly)
for i in range(Lx2,Lx2+1):
for j in range(0,Ly):
if(j < int(Ly/2)):
print(i,j,img[i,j,0],img[i,j,1],img[i,j,2])
for k in range(3):
img[i][j][0]=0;img[i][j][1]=0;img[i][j][2]=255;
print(img.shape)
cv2.imwrite('rect-3VL.png', img)
cv2.imshow('My Image 1', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
Lx= 65 Ly= 74
32 0 255 255 255
32 1 255 255 255
32 2 255 255 255
32 3 255 255 255
32 4 255 255 255 白色
32 5 255 255 255
32 6 255 255 255
32 7 255 255 255
32 8 255 255 255
32 9 255 255 255
32 10 0 0 0 黑色
32 11 0 0 0
32 12 255 255 255
32 13 255 255 255
32 14 255 255 255
32 15 255 255 255
32 16 255 255 255
32 17 255 255 255
32 18 255 255 255 白色
32 19 255 255 255
32 20 255 255 255
32 21 255 255 255
32 22 255 255 255
32 23 255 255 255
32 24 36 28 237
32 25 36 28 237 紅色
32 26 255 255 255
32 27 255 255 255
32 28 255 255 255 白色
32 29 255 255 255
32 30 255 255 255
32 31 255 255 255
32 32 232 162 0
32 33 232 162 0
32 34 232 162 0 藍色
32 35 232 162 0
32 36 232 162 0
(65, 74, 3)
|
|
- 將兩個圖片直接合成
要將兩個圖片所對應的陣列相加,首要條件是要先調整兩個陣列的行列尺度,然後相對應的矩陣元素相加,並且要遵循uint8的運算法則。
import cv2
img1=cv2.imread('LAN1.png')
img2=cv2.imread('LAN2.png')
print(img1.shape,img2.shape)
i1=img1[:450,:600,0:3]
i2=img2[:450,:600,0:3]
i3=i1+i2
for i in range(20): print([i1[320][i][k] for k in range(3)],end=' ')
print('\n---------------')
for i in range(20): print([i2[320][i][k] for k in range(3)],end=' ')
print('\n---------------')
for i in range(20): print([i3[320][i][k] for k in range(3)],end=' ')
print('\n---------------')
print(i1.shape,i2.shape,i3.shape)
print(type(i3[0][0][0]))
cv2.imwrite('CV_LAN1.png', i1)
cv2.imwrite('CV_LAN2.png', i2)
cv2.imwrite('CV_LAN3.png', i3)
cv2.imshow('MY i1',i1)
cv2.imshow('MY i2',i2)
cv2.imshow('MY i3',i3)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
(480, 640, 3) (470, 620, 3)
[133, 133, 133] [133, 133, 133] [136, 136, 136] [137, 137, 137]
[137, 137, 137] [137, 137, 137] [137, 137, 137] [135, 135, 135]
[142, 142, 142] [138, 138, 138] [139, 139, 139] [138, 138, 138]
[138, 138, 138] [138, 138, 138] [137, 137, 137] [139, 139, 139]
[138, 138, 138] [140, 140, 140] [139, 139, 139] [137, 137, 137]
---------------
[152, 152, 152] [151, 151, 151] [150, 150, 150] [150, 150, 150]
[151, 151, 151] [151, 151, 151] [152, 152, 152] [152, 152, 152]
[151, 152, 152] [149, 150, 150] [151, 151, 151] [152, 152, 152]
[152, 152, 152] [152, 152, 152] [152, 152, 152] [153, 153, 153]
[152, 152, 152] [151, 151, 151] [153, 153, 153] [153, 153, 153]
---------------
[29, 29, 29] [28, 28, 28] [30, 30, 30] [31, 31, 31] [32, 32, 32]
[32, 32, 32] [33, 33, 33] [31, 31, 31] [37, 38, 38] [31, 32, 32]
[34, 34, 34] [34, 34, 34] [34, 34, 34] [34, 34, 34] [33, 33, 33]
[36, 36, 36] [34, 34, 34] [35, 35, 35] [36, 36, 36] [34, 34, 34]
---------------
(450, 600, 3) (450, 600, 3) (450, 600, 3)
133+152-256=29
|
- 將多個圖片疊合
import numpy as np
import cv2
img1=cv2.imread('num01.png')
img2=cv2.imread('num02.png')
i1=img1[:60,:60,:]
i2=img2[:60,:60,:]
#imgB=np.vstack((img1,img2)) # cause error with non-equal size
imgA=np.vstack((i1,i2))
print(img1.shape,img2.shape)
print(i1.shape,i2.shape,imgA.shape)
cv2.imshow('MY imgA', imgA)
i3=np.copy(i1)
i4=np.copy(i2)
vstk1 = np.concatenate((i1, i2), axis=0)
vstk2 = np.concatenate((i3, i4), axis=0)
stk=np.concatenate((vstk1, vstk2), axis=1)
cv2.imshow('MY stk', stk)
print(img1.shape,vstk1.shape,vstk2.shape,stk.shape)
cv2.imwrite('SQ_GSTK.png', stk)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
(79, 75, 3) (77, 74, 3)
(60, 60, 3) (60, 60, 3) (120, 60, 3)
(79, 75, 3) (120, 60, 3) (120, 60, 3) (120, 120, 3)
|
|
- 圖片中加入直線可以使用 cv2.line 函數
import numpy as np
import cv2
img = np.zeros((256, 256, 3), np.uint8)
img.fill(200)
cv2.line(img, (0, 0), (255, 255), (0, 0, 255), 5)
cv2.imshow('My Image', img)
cv2.imwrite('cv2line.png', img)
cv2.waitKey(0)
|
|
- openCV的畫圖函數-範例
import numpy as np
import cv2
img = np.zeros((256, 256, 3), np.uint8)
img.fill(200)
# 在圖片上畫一條紅色的對角線,寬度為 5 px
# cv2.line(影像, 開始座標, 結束座標, 顏色, 線條寬度)
cv2.line(img, (0, 0), (255, 255), (0, 0, 255), 5)
#cv2.rectangle(影像, 頂點座標, 對向頂點座標, 顏色, 線條寬度)
cv2.rectangle(img, (20, 60), (120, 160), (0, 255, 0), 2)
#cv2.circle(影像, 圓心座標, 半徑, 顏色, 線條寬度)
cv2.circle(img,(90, 210), 30, (0, 255, 255), 3)
cv2.circle(img,(140, 170), 15, (255, 0, 0), -1)
cv2.ellipse(img, (180, 200), (25, 55), 45, 0, 360, (205, 0, 255), 2)
cv2.ellipse(img, (180, 200), (20, 50), 45, 0, 180, (255, 0, 255), -1)
cv2.putText(img, 'ov05.py', (10, 40), cv2.FONT_HERSHEY_SIMPLEX,
1, (0, 0, 0), 1, cv2.LINE_AA)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
|