1. 程式人生 > 實用技巧 >OpenCV計算機視覺學習(1)——影象基本操作(影象視訊讀取,ROI區域擷取,常用cv函式解釋)

OpenCV計算機視覺學習(1)——影象基本操作(影象視訊讀取,ROI區域擷取,常用cv函式解釋)

人工智慧學習離不開實踐的驗證,推薦大家可以多在FlyAI-AI競賽服務平臺多參加訓練和競賽,以此來提升自己的能力。FlyAI是為AI開發者提供資料競賽並支援GPU離線訓練的一站式服務平臺。每週免費提供專案開源演算法樣例,支援演算法能力變現以及快速的迭代演算法模型。

如果需要處理的原圖及程式碼,請移步小編的GitHub地址

  傳送門:請點選我

  如果點選有誤:https://github.com/LeBron-Jian/ComputerVisionPractice

1,計算機眼中的影象

  我們開啟經典的 Lena圖片,看看計算機是如何看待圖片的:

  我們點選圖中的一個小格子,發現計算機會將其分為R,G,B三種通道。每個通道分別由一堆0~256之間的數字組成,那OpenCV如何讀取,處理圖片呢,我們下面詳細學習。

2,影象的載入,顯示和儲存

  我們看看在OpenCV中如何操作:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

import cv2

# 生成圖片

img = cv2.imread("lena.jpg")

# 生成灰色圖片

imgGrey = cv2.imread("lena.jpg", 0)

# 展示原圖

cv2.imshow("img", img)

# 展示灰色圖片

cv2.imshow("imgGrey", imgGrey)

# 等待圖片的關閉

cv2.waitKey()

# 儲存灰色圖片

cv2.imwrite("Copy.jpg", imgGrey)

  影象的顯示,也可以建立多個視窗。

2.1 影象的載入函式 cv2.imread()

  cv2.imread()函式原型如下:

1

imread(filename, flags=None)

  使用函式cv2.imread() 讀入影象。這幅影象應該在此程式的工作路徑,或者給函式提供完整路徑,第二個引數是要告訴函式應該如何讀取這幅圖片。

  • cv2.IMREAD_COLOR:讀入一副彩色影象。影象的透明度會被忽略,這是預設引數
  • cv2.IMREAD_GRAYSCALE:以灰度模式讀入影象
  • cv2.IMREAD_UNCHANGED:
    保留讀取圖片原有的顏色通道
  • +1 :等同於cv2.IMREAD_COLOR
  • 0 :等同於cv2.IMREAD_GRAYSCALE
  • -1 :等同於cv2.IMREAD_UNCHANGED

  PS:呼叫opencv,就算影象的路徑是錯的,OpenCV 也不會提醒你的,但是當你使用命令 print(img) 時得到的結果是None。

2.2 影象的顯示函式 cv2.imshow()

  cv2.imshow()函式作用是在視窗中顯示影象,視窗自動適合於影象大小,我們也可以通過imutils模組調整顯示影象的視窗大小。

  函式官方定義如下:

1

imshow(winname, mat)

  引數解釋如下:

  • 引數一: 視窗名稱(字串)
  • 引數二: 影象物件,型別是numpy中的ndarray型別,注:這裡可以通過imutils模組改變影象顯示大小

2.3 影象的儲存函式 cv2.imwrite()

  cv2.imwrite() 函式檢查影象儲存到本地,官方定義如下:

1

cv2.imwrite(image_filename, image)

  引數解釋如下:

  • 引數一: 儲存的影象名稱(字串)
  • 引數二: 影象物件,型別是numpy中的ndarray型別

3,影象顯示視窗建立與銷燬

  當我們使用imshow函式展示影象時,最後需要在程式中對影象展示視窗進行銷燬,否則程式將無法正常終止,常用的銷燬視窗的函式有下面兩個:

1

2

3

4

(1)、cv2.destroyWindow(windows_name) #銷燬單個特定視窗

引數: 將要銷燬的視窗的名字

(2)、cv2.destroyAllWindows() #銷燬全部視窗,無引數

  那我們合適銷燬視窗,肯定不能圖片視窗一出現我們就將視窗銷燬,這樣便沒法觀看視窗,試想有兩種方式:

  • (1) 讓視窗停留一段時間然後自動銷燬;
  • (2) 接收指定的命令,如接收指定的鍵盤敲擊然後結束我們想要結束的視窗

  以上兩種情況都將使用cv2.waitKey函式, 首先產看函式定義:

1

cv2.waitKey(time_of_milliseconds)

  唯一引數delay是整數,可正可負也可是零,含義和操作也不同,分別對應上面說的兩種情況。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

(1) time_of_milliseconds > 0 :

此時time_of_milliseconds表示時間,單位是毫秒,

含義表示等待 time_of_milliseconds毫秒後圖像將自動銷燬,看以下示例

#表示等待10秒後,將銷燬所有影象

ifcv2.waitKey(10000):

cv2.destroyAllWindows()

#表示等待10秒,將銷燬視窗名稱為'origin image'的影象視窗

ifcv2.waitKey(10000):

cv2.destroyWindow('origin image')

(2) time_of_milliseconds <= 0 :

此時影象視窗將等待一個鍵盤敲擊,接收到指定的鍵盤敲擊便會進行視窗銷燬。

我們可以自定義等待敲擊的鍵盤,通過下面的例子進行更好的解釋

#當指定waitKey(0) == 27時當敲擊鍵盤 Esc 時便銷燬所有視窗

ifcv2.waitKey(0) == 27:

cv2.destroyAllWindows()

#當接收到鍵盤敲擊A時,便銷燬名稱為'origin image'的影象視窗

ifcv2.waitKey(-1) == ord('A'):

cv2.destroyWindow('origin image')

  

  waitKey()函式原型:

1

2

3

C++:intwaitKey(intdelay=0) Python: cv2.waitKey([delay]) → retval

C:intcvWaitKey(intdelay=0 ) Python: cv.WaitKey(delay=0) →int

  waitKey()函式功能:

  waitKey() 函式的功能是不斷地重新整理影象,頻率時間為delay,單位為ms。返回值為當前鍵盤按鍵值。

  waitKey()函式作用:

  1,waitKey() 這個函式是在一個給定的時間內(單位ms)等待使用者按鍵觸發;如果使用者沒有按下鍵,則繼續等待(迴圈)。

  2,如果設定waitKey(0),則表示程式會無限制的等待使用者的按鍵事件。

  3,用OpenCV來顯示影象或者視訊時,如果後面不加cvWaitKey這個函式,基本上是顯示不出來的。

  4,顯示影象,一般要在cvShowImage()函式後面加一句cvWaitKey(0);否則影象無法正常顯示。

  waitKey()原始碼:

+ View Code

指定視窗大小模式的屬性:

  • cv2.WINDOW_AUTOSIZE:根據影象大小自動建立大小
  • cv2.WINDOW_NORMAL:視窗大小可調整

1

2

# 設定為WINDOW_NORMAL可以任意縮放

# cv.namedWindow('input_image', cv.WINDOW_NORMAL)

  程式碼如下:

1

2

3

4

5

6

7

8

import cv2

img = cv2.imread("lena.jpg")

cv2.namedWindow("img", cv2.WINDOW_NORMAL)

cv2.imshow("img", img)

cv2.waitKey()

cv2.destroyAllWindows()

4,視訊的讀取,處理與儲存

  cv2.VideoCapture(): 可以捕獲攝像頭,用數字來控制不同的裝置,例如0,1。如果是視訊檔案,直接指定好路徑即可。裝置索引只是指定哪臺攝像機的號碼,0代表第一臺攝像機,1代表第二臺攝像機。之後就可以逐幀捕獲視訊,但最後,不要忘記釋放捕獲。

  cap.read():返回一個布林值(True / False)。如果幀被正確讀取,則返回true,否則返回false。可以通過檢查這個返回值來判斷視訊是否結束。  

  cap.isOpened():檢查cap是否被初始化。若沒有初始化,則使用cap.open()開啟它。當cap沒有初始化時,上面的程式碼會報錯。  

  retval,image= cv2.VideoCapture.read([,image]) 抓取,解碼並返回下一個視訊幀。返回值為true表明抓取成功。該函式是組合了grab()和retrieve(),這是最方便的方法。如果沒有幀,該函式返回false,並輸出空影象。
  retval, image = cv2.VideoCapture.retrieve([, image[, flag]]) 解碼並返回抓取的視訊幀
  retval = cv2.VideoCapture.grab() 從視訊檔案或相機中抓取下一幀。true為抓取成功。該函式主要用於多攝像頭時。
  cv2.VideoCapture.release() 關閉視訊檔案或相機裝置。

  cap.get(propId):訪問視訊的某些功能,其中propId是一個從0到18的數字,每個數字表示視訊的屬性(Property Identifier)。其中一些值可以使用cap.set(propId,value)進行修改,value是修改後的值。
  舉個例子:我通過cap.get(3)和cap.get(4)來檢查幀的寬度和高度,預設的值是640x480。但我想修改為320x240,可以使用ret = cap.set(3, 320)和ret = cap.set(4, 240)。

propId 常見取值如下:

  • cv2.CAP_PROP_POS_MSEC: 視訊檔案的當前位置(ms)
  • cv2.CAP_PROP_POS_FRAMES: 從0開始索引幀,幀位置。
  • cv2.CAP_PROP_POS_AVI_RATIO:視訊檔案的相對位置(0表示開始,1表示結束)
  • cv2.CAP_PROP_FRAME_WIDTH: 視訊流的幀寬度。
  • cv2.CAP_PROP_FRAME_HEIGHT: 視訊流的幀高度。
  • cv2.CAP_PROP_FPS: 幀率
  • cv2.CAP_PROP_FOURCC: 編解碼器四字元程式碼
  • cv2.CAP_PROP_FRAME_COUNT: 視訊檔案的幀數
  • cv2.CAP_PROP_FORMAT: retrieve()返回的Mat物件的格式。
  • cv2.CAP_PROP_MODE: 後端專用的值,指示當前捕獲模式
  • cv2.CAP_PROP_BRIGHTNESS:影象的亮度,僅適用於支援的相機
  • cv2.CAP_PROP_CONTRAST: 影象對比度,僅適用於相機
  • cv2.CAP_PROP_SATURATION:影象飽和度,僅適用於相機
  • cv2.CAP_PROP_HUE: 影象色調,僅適用於相機
  • cv2.CAP_PROP_GAIN: 影象增益,僅適用於支援的相機
  • cv2.CAP_PROP_EXPOSURE: 曝光,僅適用於支援的相機
  • cv2.CAP_PROP_CONVERT_RGB:布林標誌,指示是否應將影象轉換為RGB。

  視訊讀取與處理程式碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

import cv2

# 引數為視訊檔案目錄

videoc = cv2.VideoCapture('test.mp4')

# VideoCapture物件,引數可以是裝置索引或視訊檔名稱,裝置索引只是指定哪臺攝像機的號碼

# 0代表第一臺攝像機,1代表第二臺攝像機,之後可以逐幀捕獲視訊,但是最後需要釋放捕獲

# 呼叫內建攝像頭

# cap = cv2.VideoCapture(0)

# 呼叫USB攝像頭

# cap = cv2.VideoCapture(1)

# 檢查是否開啟正確

ifvideoc.isOpened():

open, frame = videoc.read()

else:

open = False

# 逐幀顯示實現視訊播放

whileopen:

ret, frame = videoc.read() # 讀取

ifframeisNone:

break

ifret == True:

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

cv2.imshow('result', gray)

ifcv2.waitKey(10) & 0xFF == 27: # 讀取完自動退出

# if cv2.waitKey(1) & 0xFF == ord('q'): # 讀完按 q 退出

break

# 釋放攝像頭物件和視窗

videoc.release()

cv2.destroyAllWindows()

  解釋一下從檔案中播放視訊: 和從相機捕獲視訊相同,只需要更改相機索引和視訊檔名。在顯示幀時,選擇適當地 cv2.waitKey() 時間,如果該值太小,視訊會非常快,如果他太大,則視訊會非常慢(這可以用慢動作顯示視訊)。正常情況下 25毫秒即可。

  儲存視訊:我們需要建立一個 VideoWriter物件,指定輸出檔名(例如:output.avi)。之後指定 FourCC程式碼(FourCC是用於指定視訊編碼解碼器的四位元組程式碼,可用的程式碼列標:http://www.fourcc.org/codecs.php)。接下來傳遞每秒幀數(FPS)和幀大小,最後一個是 isColor標註,如果他為TRUE,編碼器編碼成彩色幀,否則編碼成灰度框幀。

  視訊儲存程式碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

import numpyasnp

import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object

fourcc = cv2.VideoWriter_fourcc(*'XVID')

out= cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

while(cap.isOpened()):

ret, frame = cap.read()

ifret==True:

frame = cv2.flip(frame,0)

# write the flipped frame

out.write(frame)

cv2.imshow('frame',frame)

ifcv2.waitKey(1) & 0xFF == ord('q'):

break

else:

break

# Release everything if job is finished

cap.release()

out.release()

cv2.destroyAllWindows()

OpenCV提供了介面VideoWriter 用於視訊的儲存:

1

<VideoWriterobject> = cv.VideoWriter( filename, fourcc, fps, frameSize[, isColor] )


函式引數:

  • filename:給要儲存的視訊起個名字
  • fourcc:指定視訊編解碼器的4位元組程式碼
  1. 【(‘P’,‘I’,‘M’,‘1’)是MPEG-1編解碼器】
  2. 【(‘M’,‘J’,‘P’,'G ')是一個運動jpeg編解碼器】
  • fps:幀率
  • frameSize:幀大小
  • retval = cv2.VideoWriter_fourcc( c1, c2, c3, c4 ) 將4字串接為fourcc程式碼。
  • cv.VideoWriter.write( image ) 將幀影象儲存為視訊檔案。
  • isColor:如果為true,則視訊為彩色,否則為灰度視訊,預設為true

5,影象ROI

  ROI(Region of Interest)表示感興趣區域。感興趣區域,就是我們從影象中選擇一個影象區域,這個區域就是影象分析所關注的焦點。我們圈定這個區域,那麼我們要處理的影象就是要從一個大影象變為小影象區域了,這樣以便進行進一步處理,可以大大減少處理時間。

  ROI 也是使用Numpy 索引來獲得的,其本質上是多維陣列(矩陣)的切片,如下圖所示:

  其實,原理很簡單,就是利用陣列切片和索引操作來選擇指定區域的內容,通過畫素矩陣可以直接獲取ROI區域,如 img[200:400, 200: 400]。Rect 四個形參分別是:x座標,y座標,長,高,注意(x, y)指的是矩形的左上角點。

  比如我要獲取歐文的頭,圖如下:

  簡易的矩形ROI區域獲取程式碼如下

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

import cv2

import numpyasnp

import matplotlib.pyplotasplt

# 讀取原始影象

img = cv2.imread('irving.jpg')

# print(img.shape) # (458, 558, 3)

# 我們自己計算要獲取的頭部的大小,以及左上角的座標

# 這裡左上角的座標為:w:h=250 7 區域為100*100

roi_zero = img[7:107, 250:350]

# 顯示影象

cv2.imshow("Image", roi_zero)

# 等待顯示

cv2.waitKey(0)

cv2.destroyAllWindows()

  結果如下:

6,影象寬,高,通道數獲取

  img.shape 返回影象高(影象矩陣的行數),寬(影象矩陣的列數)和通道數3個屬性組成的元組,若影象是非彩色圖(即灰度圖,二值圖等),則只返回高和寬組成的元組。

1

2

3

4

5

6

7

8

9

10

import cv2

img = cv2.imread("1.jpg")

imgGrey = cv2.imread("1.jpg", 0)

sp1 = img.shape

sp2 = imgGrey.shape

print(sp1)

print(sp2)# ======輸出=======#(1200, 1920, 3)#(1200, 1920)

7,影象畫素數目和影象資料型別的獲取

  影象矩陣img 的 size屬性和 dtype 分別對應影象的畫素總數目和影象資料型別。一般情況下,影象的資料型別是 uint8。

  通過size關鍵字獲取影象的畫素數目,其中灰度影象返回行數*列數彩色影象返回行數*列數*通道數

  通過dtype關鍵字獲取影象的資料型別,通常返回 uint8

  程式碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

# -*- coding:utf-8 -*-

import cv2

import numpy

#讀取圖片

img = cv2.imread("test.jpg", cv2.IMREAD_UNCHANGED)

#獲取影象形狀

print(img.shape)

#獲取畫素數目

print(img.size)

#獲取影象型別

print(img.dtype)

  結果如下:

1

2

3

4

5

(615, 327, 3)

603315 # 603315=615*327*3

uint8

  注意1:如果影象是灰度圖,返回值僅有行數和列數,所以通過檢查這個返回值就可以知道載入的是灰度圖還是彩色圖。img.size可以返回影象的畫素數目。

  注意2:在debug時, img.dtype 非常重要,因為在OpenCV Python程式碼中經常出現數據型別的不一致。

8,生成指定大小的空影象

  生成指定大小的空圖形,方便我們後續填充,空圖形是黑色的圖(因為指定的是0)。

1

2

3

4

5

6

7

8

9

10

11

12

13

import cv2

import numpyasnp

img = cv2.imread("1.jpg")

imgZero = np.zeros(img.shape, np.uint8)

imgFix = np.zeros((300, 500, 3), np.uint8)

# imgFix = np.zeros((300,500),np.uint8)

cv2.imshow("img", img)

cv2.imshow("imgZero", imgZero)

cv2.imshow("imgFix", imgFix)

cv2.waitKey()

 

9,訪問和操作影象畫素

  OpenCV中影象矩陣的順序是 B,G,R。可以直接通過座標位置訪問和操作影象畫素。

1

2

3

4

5

6

7

8

9

10

import cv2

img = cv2.imread("01.jpg")

numb = img[50,100]

print(numb)

img[50,100] = (0,0,255)

cv2.imshow("img",img)

cv2.waitKey()

  分開訪問影象某一通道畫素值也非常方便(下面程式碼將影象變為白色,即255):

1

2

3

4

5

6

7

8

9

10

import cv2

img = cv2.imread("01.jpg")

img[0:100,100:200,0] = 255

img[100:200,200:300,1] = 255

img[200:300,300:400,2] = 255

cv2.imshow("img",img)

cv2.waitKey()

  Python中,更改影象某一矩形區域的畫素值也很方便。

1

2

3

4

5

6

7

8

import cv2

img = cv2.imread("01.jpg")

img[0:50,1:100] = (0,0,255)

cv2.imshow("img",img)

cv2.waitKey()

  注意:優化

  首先我們需要讀入一幅影象,然後根據畫素的行和列的座標獲取它的畫素值。對BGR影象而言,返回值為B,G,R的值,對灰度影象而言,會返回它的灰度值(亮度? intensity)

1

2

3

4

5

6

7

8

9

10

11

12

13

import cv2

import numpyasnp

img=cv2.imread('test.jpg')

px=img[100,100]

print(px)

blue=img[100,100,0]

print(blue)

# 我們可以使用類似的方式修改畫素值

img[100,100]=[255,255,255]

print(img[100,100])

## [255 255 255]

  注意1:Numpy 是經過優化了的進行快速矩陣運算的軟體包,所以我們不推薦逐個獲取畫素值並修改,這樣會很慢,能有矩陣運算就不要迴圈。

  注意2:上面提到的方法被用來選取矩陣的一個區域,比如說 前 5行的後3列。對於獲取每一個畫素值,也許使用Numpy 的 array.item() 和 array.itemset() 會更好,但是返回是標量。如果你想獲得所有 B,G,R的值,你需要使用 array.item() 分割他們。

  獲取畫素值及其修改的更好的方法

1

2

3

4

5

6

7

8

9

import cv2

import numpyasnp

img=cv2.imread('test.jpg')

print(img.item(10,10,2))

img.itemset((10,10,2),100)

print(img.item(10,10,2))

# 59

# 100

  

10,影象顏色通道分離與合併

  分離影象通道可以使用 cv2中 split函式,合併則可以使用 merge函式。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

import cv2

img = cv2.imread("01.jpg")

b , g , r = cv2.split(img)

# b = cv2.split(img)[0]

# g = cv2.split(img)[1]

# r = cv2.split(img)[2]

merged = cv2.merge([b,g,r])

cv2.imshow("Blue",b)

cv2.imshow("Green",g)

cv2.imshow("Red",r)

cv2.imshow("Merged",merged)

cv2.waitKey()

   有時候,我們需要對 BGR 三個通道分別進行操作,這時你就需要把BGR拆分成單個通道,有時你需要把獨立通道的圖片合成一個BGR影象。下面學習一下拆分及其合併影象通道的cv函式  

  程式碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

# _*_coding:utf-8_*_

import cv2

import numpyasnp

def split_image(img_path):

img = cv2.imread(img_path)

print(img.shape) # (800, 800, 3)

# b, g, r = cv2.split(img)

b = img[:, :, 0]

g = img[:, :, 1]

r = img[:, :, 2]

cv2.imshow('b', b)

# cv2.imshow('g', g)

# cv2.imshow('r', r)

cv2.waitKey(0)

cv2.destroyAllWindows()

def merge_image(img_path):

img = cv2.imread(img_path)

b, g, r = cv2.split(img)

img = cv2.merge([b, g, r])

cv2.imshow('merge', img)

cv2.waitKey(0)

cv2.destroyAllWindows()

if__name__ =='__main__':

img_path ='durant.jpg'

split_image(img_path)

# merge_image(img_path)

  注意:這裡拆分寫了兩個方法,為什麼呢?就是因為 cv2.split()是一個比較耗時的操作,只有真正需要時才用它,能用Numpy索引就儘量使用索引。

  原圖:

  B,G,R 三種通道的圖片:

  合併後的圖片

  假設,我們想是所有畫素的紅色通道值都為0,我們不必先拆分再賦值,我們可以直接使用 Numpy 索引,這樣會更快:

1

2

3

4

5

6

7

8

9

10

11

def assign_image(img_path):

img = cv2.imread(img_path)

img[:, :, 1] = 0

cv2.imshow('assign', img)

cv2.waitKey(0)

cv2.destroyAllWindows()

if__name__ =='__main__':

img_path ='durant.jpg'

assign_image(img_path)

  結果如下:

11,在影象上輸出文字

使用putText函式在圖片上輸出文字,函式原型:

1

putText(img, text, org, fontFace, fontScale, color, thickness=None, lineType=None, bottomLeftOrigin=None)

  引數意思:

      1. img: 影象
      2. text:要輸出的文字
      3. org: 文字的起點座標
      4. fontFace: 字型
      5. fontScale: 字型大小
      6. color: 字型顏色
      7. thickness: 字圖加粗

   程式碼如下:

1

2

3

4

5

6

7

8

import cv2

img = cv2.imread("durant.jpg")

cv2.putText(img,"durant is my favorite super star", (100, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255))

cv2.imshow("img", img)

cv2.waitKey()

  圖如下:

12, 影象縮放

  cv2.resize()函式是來調整圖片的大小,改變圖片尺寸。

  注意:CV2是BGR,而我們讀取的圖片是RGB,所以要注意一下,變換的時候注意對應。

  其函式原型如下:

1

def resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)

  對應的各個引數意思:

  src:輸入,原影象,即待改變大小的影象;

  dsize:輸出影象的大小。如果這個引數不為0,那麼就代表將原影象縮放到這個Size(width,height)指定的大小;如果這個引數為0,那麼原影象縮放之後的大小就要通過下面的公式來計算:

              dsize = Size(round(fx*src.cols), round(fy*src.rows))

其中,fx和fy就是下面要說的兩個引數,是影象width方向和height方向的縮放比例。

  fx:width方向的縮放比例,如果它是0,那麼它就會按照(double)dsize.width/src.cols來計算;

  fy:height方向的縮放比例,如果它是0,那麼它就會按照(double)dsize.height/src.rows來計算;

  interpolation:這個是指定插值的方式,影象縮放之後,肯定畫素要進行重新計算的,就靠這個引數來指定重新計算畫素的方式,有以下幾種:

  • INTER_NEAREST - 最鄰近插值
  • INTER_LINEAR - 雙線性插值,如果最後一個引數你不指定,預設使用這種方法
  • INTER_AREA - 使用畫素區域關係進行重取樣 resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to theINTER_NEARESTmethod.
  • INTER_CUBIC -4x4畫素鄰域內的雙立方插值
  • INTER_LANCZOS4 -8x8畫素鄰域內的Lanczos插值

  對於插值方法,正常情況下使用預設的雙線性插值法就夠了。幾種常用方法的效率為:

最鄰近插值>雙線性插值>雙立方插值>Lanczos插值

  但是效率和效果是反比的,所以根據自己的情況酌情使用。

  注意:輸出的尺寸格式為(寬,高)

  示例:

1

2

3

4

5

6

7

8

# _*_coding:utf-8_*_

import cv2

image = cv2.imread('TestData\\arial_qz8Shv_10.png')

# 對圖片進行灰度化,注意這裡變換!!

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

crop_img = cv2.resize(gray, (224, 224), interpolation=cv2.INTER_LANCZOS4)

  對影象縮放,做一個完整的示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

import cv2

import os

import numpyasnp

import matplotlib.pyplotasplt

img = cv2.imread("cat.jpg")

# resize的插值方法:正常情況下使用預設的雙線性插值法

res_img = cv2.resize(img, (200, 100))

res_fx = cv2.resize(img, (0, 0), fx=0.5, fy=1)

res_fy = cv2.resize(img, (0, 0), fx=1, fy=0.5)

print('origin image shape is ',img.shape)

print('resize 200*100 image shape is ',res_img.shape)

print('resize 0.5:1 shape is ',res_fx.shape)

print('resize 1:0.5 image shape is ',res_fy.shape)

'''

origin image shapeis(414, 500, 3)

resize 200*100 image shapeis(100, 200, 3)

resize 0.5:1 shapeis(414, 250, 3)

resize 1:0.5 image shapeis(207, 500, 3)

'''

# 標題

title = ['Origin Image','resize200*100','resize_fx/2','resize_fy/2']

# 對應的影象

image = [img, res_img, res_fx, res_fy]

foriinrange(len(image)):

plt.subplot(2, 2, i+1), plt.imshow(image[i])

plt.title(title[i])

plt.xticks([]), plt.yticks([])

plt.show()

  效果圖如下:

  

13 cv2.cvtColor()函式用法介紹

  在日常生活中,我們看到的大多數彩色影象都是RGB型別,但是在影象處理過程中,常常需要用到灰度影象、二值影象、HSV、HSI等顏色,OpenCV提供了cvtColor()函式實現這些功能。其函式原型如下所示:

1

cvtColor(src, code, dst=None, dstCn=None)

  變數含義:

  • src表示輸入影象,需要進行顏色空間變換的原影象
  • dst表示輸出影象,其大小和深度與src一致
  • code表示轉換的程式碼或標識
  • dstCn表示目標影象通道數,其值為0時,則有src和code決定

  該函式的作用是將一個影象從一個顏色空間轉換到另一個顏色空間,其中,RGB是指Red、Green和Blue,一副影象由這三個通道(channel)構成;Gray表示只有灰度值一個通道;HSV包含Hue(色調)、Saturation(飽和度)和Value(亮度)三個通道。在OpenCV中,常見的顏色空間轉換標識包括CV_BGR2BGRA、CV_RGB2GRAY、CV_GRAY2RGB、CV_BGR2HSV、CV_BGR2XYZ、CV_BGR2HLS等。
  下面程式碼對比了九種常見的顏色空間,包括BGR、RGB、GRAY、HSV、YCrCb、HLS、XYZ、LAB和YUV,並迴圈顯示處理後的影象。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

#encoding:utf-8

import cv2

import numpyasnp

import matplotlib.pyplotasplt

#讀取原始影象

img_BGR = cv2.imread('durant.jpg')

#BGR轉換為RGB

img_RGB = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2RGB)

#灰度化處理

img_GRAY = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2GRAY)

#BGR轉HSV

img_HSV = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2HSV)

#BGR轉YCrCb

img_YCrCb = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2YCrCb)

#BGR轉HLS

img_HLS = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2HLS)

#BGR轉XYZ

img_XYZ = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2XYZ)

#BGR轉LAB

img_LAB = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2LAB)

#BGR轉YUV

img_YUV = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2YUV)

#呼叫matplotlib顯示處理結果

titles = ['BGR','RGB','GRAY','HSV','YCrCb','HLS','XYZ','LAB','YUV']

images = [img_BGR, img_RGB, img_GRAY, img_HSV, img_YCrCb,

img_HLS, img_XYZ, img_LAB, img_YUV]

foriinxrange(9):

plt.subplot(3, 3, i+1), plt.imshow(images[i],'gray')

plt.title(titles[i])

plt.xticks([]),plt.yticks([])

plt.show()

  效果圖如下:

  如果想檢視引數的全部型別,請執行以下程式便可查閱,總共有274種空間轉換型別:

1

2

3

import cv2

flags = [iforiindir(cv2)ifi.startswith('COLOR_')]

print(flags)

13.1, BGR2YUV

  (參考地址:https://zhuanlan.zhihu.com/p/98622289)

  OpenCV BGR 圖轉 YUV圖的的C++原始碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

// file name: convert.cpp

#include <opencv2/opencv.hpp>

// BGR 轉 YUV

voidBGR2YUV(constcv::Mat bgrImg, cv::Mat &y, cv::Mat &u, cv::Mat &v) {

cv::Matout;

cv::cvtColor(bgrImg,out, cv::COLOR_BGR2YUV);

bgr

cv::bgr channel[3];

cv::split(out, channel);

y = channel[0];

u = channel[1];

v = channel[2];

}

// YUV 轉 BGR

voidYUV2BGR(constcv::Mat y,constcv::Mat u,constcv::Mat v, cv::Mat& bgrImg) {

std::vector<cv::Mat> inChannels;

inChannels.push_back(y);

inChannels.push_back(u);

inChannels.push_back(v);

// 合併3個單獨的 channel 進一個矩陣

cv::Mat yuvImg;

cv::merge(inChannels, yuvImg);

cv::cvtColor(yuvImg, bgrImg, cv::COLOR_YUV2BGR);

}

// 使用例子

intmain() {

cv::Mat origImg = cv::imread("test.png");

cv::Mat y, u, v;

BGR2YUV(origImg, y, u, v);

cv::Mat bgrImg;

YUV2BGR(y, u, v, bgrImg);

cv::imshow("origImg", origImg);

cv::imshow("Y channel", y);

cv::imshow("U channel", u);

cv::imshow("V channel", v);

cv::imshow("converted bgrImg", bgrImg);

cv::waitKey(0);

return0;

}

  在python中測試如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

import cv2

import matplotlib.pyplotasplt

def bgr2yuv(img):

yuv_img = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)

y, u, v = cv2.split(yuv_img)

returny, u, v

def yuv2bgr(y, u, v):

yuv_img = cv2.merge([y, u, v])

bgr_img = cv2.cvtColor(yuv_img, cv2.COLOR_YUV2BGR)

returnbgr_img

def main():

orig_img = cv2.imread('durant.jpg')

gray = cv2.cvtColor(orig_img, cv2.COLOR_BGR2GRAY)

y, u, v = bgr2yuv(orig_img)

bgr_img = yuv2bgr(y, u, v)

titles = ['orig_img','gray','Y channel','U channel','V channel','bgr_img']

images = [orig_img, gray, y, u, v, bgr_img]

foriinrange(len(titles)):

plt.subplot(2, 3, i+1)

plt.imshow(images[i])

plt.title(titles[i])

plt.xticks([]), plt.yticks([])

plt.show()

if__name__ =='__main__':

main()

  圖如下:

下面區分一下YUV和YCbCr,YUV色彩模型來源於RGB模型,該模型的特點是將亮度和色度分離開,從而適合於影象處理領域。
應用:模擬領域
Y'=0.299*R'+0.587*G'+0.114*B'
U'=-0.147*R'-0.289*G'+0.436*B'=0.492*(B'-Y')
V'=0.615*R'-0.515*G'-0.100*B'=0.877*(R'-Y')
R'=Y'+1.140*V'
G'=Y'-0.394*U'-0.581*V'
B'=Y'+2.032*U'

YCbCr模型來源於YUV模型。YCbCr是YUV顏色空間的偏移版本,應用:數字視訊,ITU-RBT.601建議
Y’=0.257*R'+0.504*G'+0.098*B'+16
Cb'=-0.148*R'-0.291*G'+0.439*B'+128
Cr'=0.439*R'-0.368*G'-0.071*B'+128
R'=1.164*(Y’-16)+1.596*(Cr'-128)
G'=1.164*(Y’-16)-0.813*(Cr'-128)-0.392*(Cb'-128)
B'=1.164*(Y’-16)+2.017*(Cb'-128)

參考文獻:


https://blog.csdn.net/woainishifu/article/details/53260546

https://blog.csdn.net/eastmount/article/details/82177300

https://www.cnblogs.com/Undo-self-blog/p/8434906.html

https://www.cnblogs.com/zlel/p/9267629.html

視訊讀取:https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_gui/py_video_display/py_video_display.html

https://blog.csdn.net/qq_25436597/article/details/79621833

https://zhuanlan.zhihu.com/p/44255577

OpenCV中的rgb2Yuv轉換公式問題:https://bbs.csdn.net/topics/390713769

更多精彩內容請訪問FlyAI-AI競賽服務平臺;為AI開發者提供資料競賽並支援GPU離線訓練的一站式服務平臺;每週免費提供專案開源演算法樣例,支援演算法能力變現以及快速的迭代演算法模型。

挑戰者,都在FlyAI!!!