opencv-python學習之旅

Tanگگ發表於2022-12-28

opencv-python 操作


*注:在此筆記中只記錄下各種函式的使用,規則
詳細講解見https://opencv.apachecn.org/#/docs/4.0.0/2.1-tutorial_py_image_display

建立,讀取,顯示,儲存影像

建立影像

import numpy as np
img = np.zeros((512,512,3),np.uint8)  # 建立一個影像 ,3 是指三個通道,可傳入RGB

讀取影像

cv2.imread(“本工作目錄下的檔名”,-1或0或1) # -1:載入影像,包括alpha通道,0:灰色模式載入影像,1:預設正常模式載入

顯示影像

cv.imshow('image', img)   # imshow("視窗名字",要顯示的影像)
cv.waitKey(0)
cv.destroyAllWindows()

cv.waitKey() 是一個鍵盤繫結函式,它的引數是以毫秒為單位的時間。該函式為任意鍵盤事件等待指定毫秒。如果你在這段時間內按下任意鍵,程式將繼續。如果傳的是 0,它會一直等待鍵盤按下。它也可以設定檢測特定的擊鍵,例如,按下鍵 a 等,我們將在下面討論。

Note

除了繫結鍵盤事件,該函式還會處理許多其他 GUI 事件,因此你必須用它來實際顯示影像。
cv.destroyAllWindows() 簡單的銷燬我們建立的所有視窗。如果你想銷燬任意指定視窗,應該使用函式 cv.destroyWindow() 引數是確切的視窗名。

eg.下面的程式以灰度模式讀取影像,顯示影像,如果你按下 's‘ 會儲存和退出影像,或者按下 ESC 退出不儲存。

import numpy as np
import cv2 as cv

img = cv.imread('messi5.jpg',0)
cv.imshow('image',img)
k = cv.waitKey(0)
if k == 27: # ESC 退出
    cv.destroyAllWindows()
elif k == ord('s'): # 's' 儲存退出
    cv.imwrite('messigray.png',img)
    cv.destroyAllWindows()

Note

有一種特殊情況,你可以先建立一個視窗然後載入影像到該視窗。在這種情況下,你能指定視窗是否可調整大小。它是由這個函式完成的 cv.namedWindow()。預設情況下,flag 是 cv.WINDOW_AUTOSIZE。但如果你指定了 flag 為 cv.WINDOW_NORMAL,你能調整視窗大小。當影像尺寸太大,在視窗中新增跟蹤條是很有用的。

看下面的程式碼:

cv.namedWindow('image', cv.WINDOW_NORMAL)
cv.imshow('image',img)
cv.waitKey(0)
cv.destroyAllWindows()

儲存影像

儲存影像,用這個函式 cv.imwrite()

第一個引數是檔名,第二個引數是你要儲存的影像。

cv.imwrite('messigray.png',img)

將該影像用 PNG 格式儲存在工作目錄。

使用 Matplotlib

Matplotlib 是一個 Python 的繪相簿,提供了豐富多樣的繪圖函式。你將在接下來的文章中看到它們。在這裡,你將學習如何使用 Matplotlib 來顯示影像。你還能用 Matplotlib 縮放影像,儲存影像等。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt

img = cv.imread('messi5.jpg',0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')   # 讓影像以灰色形式展示
# 或者選擇  plt.imshow(img[:,:,::-1])    #這一步操作,保證和原影像顯示的色彩一致
plt.xticks([]), plt.yticks([]) # 隱藏 X 和 Y 軸的刻度值  去掉則會顯示刻度
plt.show()

色彩模式與cv2不一樣(BGR),因此顯示出來的顏色不對,需要改一下

plt.imshow(img[:,:,::-1])    #這一步操作,保證和原影像顯示的色彩一致
plt.show()

影像的繪製功能

畫線

去畫一條線,你需要傳遞線條的開始和結束的座標。我們將建立一個黑色影像,並在坐上角到右下角畫一條藍色的線

import numpy as np
import cv2 as cv
# 建立一個黑色的影像
img = np.zeros((512,512,3), np.uint8)
# 畫一條 5px 寬的藍色對角線
cv.line(img,(0,0),(511,511),(255,0,0),5)

cv2.line(影像,(起始座標),(終點座標),(顏色),寬度)

畫圓

畫一個圓,你需要它的圓心和半徑。我們將在上面繪製的矩形上畫一個內圓。

cv.circle(img,(447,63), 63, (0,0,255), -1)

cv.circle(影像,(圓心座標x,y),半徑,(顏色),載入方式)

畫橢圓

畫一個橢圓,你需要傳好幾個引數。一個引數是圓心位置 (x,y)。下個引數是軸的長度 (長軸長度,短軸長度)。角度是橢圓在你逆時針方向的旋轉角度。startAngle 和 endAngle 表示從長軸順時針方向測量的橢圓弧的起點和終點。如整圓就傳 0 和 360。更多細節請看 cv.ellipse() 的文件。下面是在這個影像中間畫的一個半橢圓例子。

cv.ellipse(img,(256,256),(100,50),0,0,180,(0,255,255),-1)

cv.ellipse(影像,(圓心座標),(長軸,短軸),起時角度,起點,終點,顏色,載入方式

畫矩形

cv.rectangle(img,左上角座標,右下角座標,顏色,線條厚度)

畫多邊形

畫多邊形,首先你需要頂點的做座標。將這些點組成一個形狀為 ROWSx1x2 的陣列,ROWS 是頂點數,它應該是 int32 型別。這裡我們繪製一個頂點是黃色的小多邊形。

pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
pts = pts.reshape((-1,1,2))
cv.polylines(img,[pts],True,(0,255,255))

Note

  • 如果地三個是 False,你將獲得所有點的折線,而不是一個閉合形狀。
  • cv.polylines() 能畫很多線條。只需建立你想繪製所有線條的列表,然後將其傳給這個函式。所有線條都將單獨繪製。繪製一組線條比呼叫 cv.line() 好很多,快很多。

繪圖新增文字

cv.putText(img,輸入內容,文字的放置位置,字型,字型大小,顏色,線條寬度,cv.LINE__AA)

訪問並修改畫素點

透過行列座標來進行訪問及修改

黃色為綠色和紅色的混合。所以,該影像的所有畫素值都應為R=255,G=255,B=0。

>>> import numpy as np
>>> import CV2
>>> img = CV2.imread("img/yellow.jpg")
>>> h,w,c = img.shape
#影像大小為128*128*3
>>> print(h,w,c)
128 128 3
px = img[100,100]     # 獲取某個點的畫素值

從上面的程式碼中可以看到,您可以透過行和列座標訪問畫素值。注意,對於常見的RGB 影像,OpenCV的imread函式返回的是一個藍色(Blue)值、綠色(Green)值、紅色(Red)值的陣列,維度大小為3。而對於灰度影像,僅返回相應的灰度值。

>>> img[100,100]
#OpenCV的讀取順序為B,G,R,由於影像所有畫素為黃色,因此,G=255,R=255
array([  0, 255, 255], dtype=uint8)

# 僅訪問藍色通道的畫素
>>> blue = img[100,100,0]
>>> print(blue)
0

你也可以使用同樣的方法來修改畫素值。

>>> img[100,100] = [255,255,255]
>>> print(img[100,100])
[255 255 255]

訪問屬性

影像大小

img.shape      # 變數.shape

(256,256,3)

img.shape[:2] 取彩色圖片的長、寬。

  • 使用彩色模式傳參時
cols,rows = img.shape[:2]
# 或者
cols,rows,x = img.shape
  • 使用灰色模式

    cols ,rows = img.shape
    

如果img.shape[:3] 則取彩色圖片的長、寬、通道

關於img.shape[0]、[1]、[2]
img.shape[0]:影像的垂直尺寸(高度)
img.shape[1]:影像的水平尺寸(寬度)
img.shape[2]:影像的通道數

資料型別

img.dtype

dtype('uint8')

畫素點數量

img.size

196608

影像的裁剪、拼接、翻轉、縮放等 [(https://blog.csdn.net/zh_jessica/article/details/77946346)]

縮放:

一、影像縮放
影像縮放主要使用resize函式

result = cv2.resize(src, dsize[, result[. fx[, fy[, interpolation]]]]) 記得要用新變數來接收
其中src表示原始影像,dsize表示縮放大小,fx和fy也可以表示縮放大小倍數,他們兩個(dsize或fx\fy)設定一個即可實現影像縮放

引數說明:

src - 原圖

dst - 目標影像。當引數dsize不為0時,dst的大小為size;否則,它的大小需要根據src的大小,引數fx和fy決定。dst的型別(type)和src影像相同

dsize - 目標影像大小。當dsize為0時,它可以透過以下公式計算得出:

所以,引數dsize和引數(fx, fy)不能夠同時為0

fx - 水平軸上的比例因子。當它為0時,計算公式如下:

fy - 垂直軸上的比例因子。當它為0時,計算公式如下:

interpolation - 插值方法。共有5種:
INTER_NEAREST - 最近鄰插值法
INTER_LINEAR - 雙線性插值法(預設)
INTER_AREA - 基於區域性畫素的重取樣(resampling using pixel area relation)。對於影像抽取也叫縮小影像(image decimation)來說,這可能是一個更好的方法。但如果是放大影像時,它和最近鄰法的效果類似。
INTER_CUBIC - 基於4x4畫素鄰域的3次插值法
INTER_LANCZOS4 - 基於8x8畫素鄰域的Lanczos插值

縮小影像 用INTER_AREA更好,放大影像用 INTER_CUBIC更好;
————————————————

程式碼如下:

import cv2

#讀取圖片
image = cv2.imread("E:/pythonProject/xin.jpeg")

#圖片縮放
image1 = cv2.resize(image, (200,200))     

#圖片顯示
cv2.imshow("resize", image1)
cv2.imshow("image", image)

#等待視窗
cv2.waitKey(0)

旋轉

opencv中對影像的旋轉主要是先透過getRotationMatrix2D函式得到影像的旋轉矩陣,然後再透過仿射變換函式warpAffine得到旋轉後的影像。

函式說明:

cv2.getRotationMatrix2D(center, angle, scale)
cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst

引數說明:

getRotationMatrix2D: 得到影像的旋轉矩陣

center–表示旋轉的中心點
angle–表示旋轉的角度degrees
scale–影像縮放因子
warpAffine:

src – 輸入的影像
M – 2 X 3 的變換矩陣.
dsize – 輸出的影像的size大小
dst – 輸出的影像
flags – 輸出影像的插值方法
borderMode – 影像邊界的處理方式
borderValue – 當影像邊界處理方式為BORDER_CONSTANT 時的填充值
程式碼示範:

img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape
#90度旋轉

M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
dst = cv2.warpAffine(img,M,(cols,rows))

平移

  1. 平移translate
    平移透過自定義平移矩陣以及函式warpAffine實現:

程式碼示範:

img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape
# 平移矩陣M:[[1,0,x],[0,1,y]]
M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img,M,(cols,rows))

反轉

  1. 翻轉flip
    翻轉透過函式flip實現:

函式說明:

cv2.flip(src, flipCode[, dst]) → dst
1
引數說明:

src – 輸入的影像
dst – 輸出的影像
flipCode – 翻轉模式,flipCode==0垂直翻轉(沿X軸翻轉),flipCode>0水平翻轉(沿Y軸翻轉),flipCode<0水平垂直翻轉(先沿X軸翻轉,再沿Y軸翻轉,等價於旋轉180°)
程式碼示範:

# 水平翻轉
flip_horiz_img = cv2.flip(pad_img, 1)
# 垂直翻轉
flip_verti_img = cv2.flip(pad_img, 0)
# 水平垂直翻轉
flip_horandver_img = cv2.flip(pad_img, -1)

拼接

單個影像多次拼接

import  cv2
img =cv2.imread(file_path[i])
img=cv2.hconcat([img,img,img])#水平拼接
img=cv2.vconcat([img,img,img])#垂直拼接

多個相似特徵影像拼接(開擺!)

import cv2
import numpy as np
 
 
def stitch(image):
    # 影像拼接
    # stitcher = cv2.createStitcher(False)  # OpenCV 3.X.X.X使用該方法
    stitcher = cv2.Stitcher_create(cv2.Stitcher_PANORAMA)  # OpenCV 4.X.X.X使用該方法,cv2.Stitcher_create()也可以
    status, pano = stitcher.stitch(image)
 
    # 黑邊處理
    if status == cv2.Stitcher_OK:
        # 全景圖輪廓提取
        stitched = cv2.copyMakeBorder(pano, 10, 10, 10, 10, cv2.BORDER_CONSTANT, (0, 0, 0))
        gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)
        thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
        cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
 
        # 輪廓最小正矩形
        mask = np.zeros(thresh.shape, dtype="uint8")
        (x, y, w, h) = cv2.boundingRect(cnts[0])  # 取出list中的輪廓二值圖,型別為numpy.ndarray
        cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
 
        # 腐蝕處理,直到minRect的畫素值都為0
        minRect = mask.copy()
        sub = mask.copy()
        while cv2.countNonZero(sub) > 0:
            minRect = cv2.erode(minRect, None)
            sub = cv2.subtract(minRect, thresh)
 
        # 提取minRect輪廓並裁剪
        cnts = cv2.findContours(minRect, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
        (x, y, w, h) = cv2.boundingRect(cnts[0])
        stitched = stitched[y:y + h, x:x + w]
 
        cv2.imshow('stitched', stitched)
        cv2.imwrite('stitched.jpg', stitched)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    else:
        print('影像匹配的特徵點不足')
 
 
if __name__ == "__main__":
    image1 = cv2.imread('data/space1.jpg')
    image2 = cv2.imread('data/space2.jpg')
    image3 = cv2.imread('data/space3.jpg')
    image = image1, image2, image3
    stitch(image)

(18條訊息) OpenCV-Python 影像全景拼接stitch及黑邊處理_Klein-的部落格-CSDN部落格_stitcher_create

相關文章