OpenCV介紹
OpenCV 是一個的跨平臺計算機視覺庫,可以運行在 Linux、Windows 和 Mac OS 作業系統上,它輕量級而且高效——由一系列 C 函式和少量 C++ 類構成,同時也提供了 Python 介面,實作了影像處理和計算機視覺方面的很多通用演算法,在本文中,將介紹 OpenCV 庫,包括它的主要模塊和典型應用場景,
Python安裝OpenCV
對于 Linux 和 Windows 作業系統,首需要在 shell 或 cmd 中運行以下命令安裝 NumPy:
pip install numpy
然后再安裝 OpenCV,可以選擇兩種不同版本:
- 僅安裝主模塊包
pip install opencv-python
- 安裝完整包(包括主模塊和附加模塊)
pip install opencv-contrib-python
OpenCV主要模塊
OpenCV 可以被劃分為不同模塊,其主要模塊如下:
下表整理介紹了各主要模塊的作用:
?
??
?
??
OpenCV應用場景
OpenCV 可以應用但不僅限于以下場景:二維和三維特征提取、街景影像拼接、人臉識別系統、手勢識別、人機互動、動作識別、物體識別、自動檢查和監視、分割與識別、醫學影像分析、運動跟蹤、增強現實、視頻/影像搜索與檢索、機器人與無人駕駛汽車導航與控制、駕駛員疲勞駕駛檢測等,
OpenCV影像處理基礎
影像基礎 接下來,首先從理論上介紹影像的相關概念, 影像處理中的主要問題 我們看可以把影像看作是三維世界的二維視圖,那么數字影像作為2D影像,可以使用稱為像素的有限數字集進行表示(像素的概念將在像素、顏色、通道、影像和顏色空間部分中詳細解釋),我們可以,將計算機視覺的目標定義為將這些2D資料轉換為以下內容: 新的資料表示(例如,新影像) 決策目標(例如,執行具體決策任務) 目標結果(例如,影像的分類) 資訊提取(例如,目標檢測) 在進行影像處理時,經常會遇到以下問題: 影像的模糊性,由于受到透視的影響,從而會導致影像視覺外觀的變化,例如,從不同的角度看同一個物體會產生不同的影像; 影像通常會受許多自然因素的影響,如光照、天氣、反射和運動; 影像中的一部分物件也可能會被其他物件遮擋,使得被遮擋的物件難以檢測或分類,隨著遮擋程度的增加,影像處理的任務(例如,影像分類)可能非常具有挑戰性,
為了更好的解釋上述問題,我們假設需要開發一個人臉檢測系統,該系統應足夠魯棒,以應對光斬訓天氣條件的變化;此外,該系統應該可以處理頭部的運動,檢測用戶的頭部在坐標系中每個軸上一定程度的旋轉(抬頭、搖頭和低頭,用戶可以離相機稍近或稍遠的情況),而許多人臉檢測演算法在人臉接近正面時表現出良好的性能,但是,如果一張臉不是正面的(例如,側面對著鏡頭),演算法就無法檢測到它,此外,演算法需要即使在用戶戴著眼鏡或太陽鏡時,也可能需要檢測面部(即使這會在眼睛區域產生遮擋),綜上所述,當開發一個計算機視覺專案時,我們必須綜合考慮到所有這些因素,一個很好的表征方法是有使用大量測驗影像來驗證演算法,我們也可以根據測驗影像的不同困難程度來對它們進行分類,以便于檢測演算法的弱點,提高演算法的魯棒性,
影像處理流程
完整的影像處理程式通常可以分為以下三個步驟:
- 讀取影像,影像的獲取可以有多種不同的來源(相機、視頻流、磁盤、在線資源),因此影像的讀取可能涉及多個函式,以便可以從不同的來源讀取影像;
- 影像處理,通過應用影像處理技術來處理影像,以實作所需的功能(例如,檢測影像中的貓);
- 顯示結果,將影像處理完成后的結果以人類可讀的方式進行呈現(例如,在影像中繪制邊界框,有時也可能需要將其保存到磁盤),
此外,上述第2步影像處理可以進一步分為三個不同的處理級別:
低層處理(或者在不引起歧義的情況下可以稱為預處理),通常將一個影像作為輸入,然后輸出另一個影像,可在此步驟中應用的步驟包括但不限于以下方法:噪聲消除、影像銳化、光照歸一化以及透視校正等; 中層處理:是將預處理后的影像提取其主要特征(例如采用 DNN 模型得到的影像特征),輸出某種形式的影像表示,它提取了用于影像進一步處理的主要特征,
- 高層處理:接受中層處理得到的影像特征并輸出最終結果,例如,處理的輸出可以是檢測到的人臉.
像素、顏色、通道、影像和顏色空間 在表示影像時,有多種不同的顏色模型,但最常見的是紅、綠、藍 (RGB) 模型, RGB 模型是一種加法顏色模型,其中原色 (在RGB模型中,原色是紅色 R、綠色 G 和藍色 B) 混合在一起就可以用來表示廣泛的顏色范圍, 每個原色 (R, G, B) 通常表示一個通道,其取值范圍為[0, 255]內的整數值,因此,每個通道有共256個可能的離散值,其對應于用于表示顏色通道值的總位元數 ( 2 8 = 256 2^8=256 2 8 =256),此外,由于有三個不同的通道,使用 RGB 模型表示的影像稱為24位色深影像:

在上圖中,可以看到 RGB 顏色空間的“加法顏色”屬性:
- 紅色加綠色會得到黃色
- 藍色加紅色會得到品紅
- 藍色加綠色會得到青色
- 三種原色加在一起得到白色
因此,如前所述,RGB 顏色模型中,特定顏色可以由紅、綠和藍值分量合成表示,將像素值表示為 RGB 三元組 (r, g, b),典型的 RGB顏色選擇器如下圖所示:

解析度為 800×1200 的影像是一個包含800列和1200行的網格,每個網格就是稱為一個像素,因此其中包含 800×1200=96 萬像素,應當注意,影像中有多少像素并不表示其物理尺寸(一個像素不等于一毫米),相反,像素的大小取決于為該影像設定的每英寸像素數 (Pixels Per Inch, PPI),影像的 PPI 一般設定在 [200-400] 范圍內, 計算PPI的基本公式如下: PPI=寬度(像素) / 影像寬度(英寸) PPI=高度(像素) / 影像高度(英寸)
例如,一個4×6英寸影像,影像解析度為 800×1200,則PPI是200, 影像描述 影像可以描述為2D函式 f ( x , y ) f(x, y) f(x,y),其中 ( x , y ) (x, y) (x,y) 是空間坐標,而 f ( x , y ) f(x, y) f(x,y) 是影像在點 ( x , y ) (x, y) (x,y) 處的亮度或灰度或顏色值,另外,當f(x, y)和(x, y)值都是有限離散量時,該影像也被稱為數字影像,此時:
x∈[0,h?1],其中 h h h 是影像的高度 y ∈ [ 0 , w ? 1 ] y∈ [0, w-1] y∈[0,w?1],其中 w w w 是影像的寬度 f ( x , y ) ∈ [ 0 , L ? 1 ] f(x, y)∈ [0,L-1] f(x,y)∈[0,L?1],其中 L = 256 L=256 L=256 (對于8位灰度影像)
彩色影像也可以用同樣的方式表示,只是我們需要定義三個函式來分別表示紅色、綠色和藍色值,這三個單獨的函式中的每一個都遵循與為灰度影像定義的 f ( x , y ) f(x, y) f(x,y) 函式相同的公式,我們將這三個函式的子索引 R、G 和 B 分別表示為 f R ( x , y ) f_R(x, y) f R?(x,y)、 f G ( x , y ) f_G(x, y) f G?(x,y) 和 f B ( x , y ) f_B(x, y) f B?(x,y), 同樣,黑白影像也可以表示為相同的形式,其僅需要一個函式來表示影像,且 f ( x , y ) f(x, y) f(x,y) 只能取兩個值,通常,0 表示黑色、1 表示白色, 下圖顯示了三種不同型別的影像(彩色影像、灰度影像和黑白影像):

數字影像可以看作是真實場景的近似,因為 f ( x , y ) f(x, y) f(x,y) 值是有限的離散量,此外,灰度和黑白影像每個點只對應有一個值,彩色影像每個點需要三個函式對應于影像的紅色、綠色和藍色分量,
影像檔案型別 盡管在 OpenCV 中處理的影像時,可以將影像看作 RGB 三元組的矩陣(在 RGB 影像模型情況下),但它們不一定是以這種格式創建、存盤或傳輸的,有許多不同的檔案格式,如GIF、PNG、位圖或JPEG,使用不同形式的壓縮(無損或有損)來更有效地表示影像, 下表列示了 OpenCV 支持的檔案格式及其關聯的檔案擴展名:
?
??對影像應用無損或有損壓縮演算法,可以得到比未壓縮影像占據存盤空間小的影像,其中,在無損壓縮演算法中,得到的影像與原始影像等價,也就是說,經過反壓縮程序后,得到的影像與原始影像完全等價(相同);而在有損壓縮演算法中,得到的影像并不等同于原始影像,這意味著影像中的某些細節會丟失,在許多有損壓縮演算法中,壓縮級別是可以調整的,
OpenCV中的坐標系
為了更好的展示 OpenCV 中的坐標系以及如何訪問各個像素,查看以下低解析度影像為例:

這個圖片的尺寸是 32×41 像素,也就是說,這個影像有 1312 個像素,為了進一步說明,我們可以在每個軸上添加像素計數,如下圖所示:
現在,我們來看看 ( x , y ) (x, y) (x,y) 形式的像素索引,請注意,像素索引起始值為零,這意味著左上角位于 ( 0 , 0 ) (0, 0) (0,0),而不是 ( 1 , 1 ) (1, 1) (1,1),下面的影像,索引了 4 個單獨的像素,影像的左上角是原點的坐標: 單個像素的資訊可以從影像中提取,方法與 Python 中參考陣列的單個元素相同,
OpenCV中的通道順序
在 OpenCV 使用中,使用的顏色通道順序為 BGR 顏色格式而不是 RGB 格式,可以在下圖中看到三個通道的順序:

BGR 影像的像素結構如下圖所示,作為演示,圖示詳細說明了如何訪問pixel(y=n, x=1):

Tips:OpenCV 的最初開發人員選擇了 BGR 顏色格式(而不是 RGB 格式),是因為當時 BGR 顏色格式在軟體供應商和相機制造商中非常流行,因此選擇 BGR 是出于歷史原因,
此外,也有其他 Python 包使用的是 RGB 顏色格式(例如,Matplotlib 使用 RGB 顏色格式,Matplotlib 是最流行的 2D Python 繪圖庫,提供多種繪圖方法,可以查看 Python-Matplotlib 可視化獲取更多詳細資訊),因此,我們需要知道如何將影像從一種格式轉換為另一種格式
當我們掌握了將影像從一種格式轉換為另一種格式的方法后,就可以選擇使用 OpenCV 進行影像處理,同時利用 Matplotlib 包提供的函式來顯示影像,接下來,讓我們看看如何處理兩個庫采用的不同顏色格式, 首先,我們使用 cv2.imread() 函式加載影像:
import cv2
img_OpenCV = cv2.imread('sigonghuiye.jpeg')
影像存盤在 img_OpenCV 變數中,因為 cv2.imread() 函式以 BGR 順序加載影像,然后,我們使用 cv2.split() 函式將加載的影像分成三個通道 (b, g, r) ,這個函式的引數就是我們要分割的影像: b, g, r = cv2.split(img_OpenCV)
下一步是合并通道(以便根據通道提供的資訊構建新影像),但合并時順序與原影像不同,我們更改 b 和 r 通道的順序以遵循 RGB 格式,即我們所需要的 Matplotlib 格式:
img_matplotlib = cv2.merge([r, g, b])
此時,我們有兩個影像 (img_OpenCV 和 img_matplotlib),接下來,我們將分別使用 OpenCV 和 Matplotlib 繪制她們,以便我們可以對比結果,首先,我們將用 Matplotlib 顯示這兩個影像,
為了在同一個視窗中使用 Matplotlib 顯示兩個影像,我們將使用 subplot,它將多個影像放置在同一個視窗中,可以在 subplot 中使用三個引數,例如 subplot(m,n,p),此時,子圖處理 m × n m \times n m×n 網格中的圖,其中 m m m 確定行數, n n n 確定列數,而 p p p 確定要在網格中放置圖的位置,要使用 Matplotlib 顯示影像,需要使用 imshow 函式,
在這種情況下,當我們水平顯示兩個影像時, m = 1 m = 1 m=1、 n = 2 n = 2 n=2 ,我們將對第一個子圖 (img_OpenCV) 使用 p = 1 p = 1 p=1,對第二個子圖(img_matplotlib) 使用 p = 2 p = 2 p=2:
from matplotlib import pyplot as plt plt.subplot(121) plt.imshow(img_OpenCV) plt.subplot(122) plt.imshow(img_matplotlib) plt.show()
程式輸出如下圖所示:
可以看出,第一個子圖以錯誤的顏色( BGR 順序)顯示影像,而第二個子圖以正確的顏色( RGB 順序)顯示影像,接下來,我們使用 cv2.imshow() 顯示兩個影像:
cv2.imshow('bgr image', img_OpenCV)
cv2.imshow('rgb image', img_matplotlib)
cv2.waitKey(0)
cv2.destroyAllWindows()
以下螢屏截圖顯示了執行上述代碼獲得的結果:
正如預期的那樣,螢屏截圖中,第一張圖以正確的色彩顯示影像,而第二張圖以錯誤的顏色顯示影像,
此外,如果我們想在同一個視窗中顯示兩個影像,可以構建一個包含這兩個影像的拼接影像,將兩張圖片水平連接起來,為此,我們需要使用 NumPy 的 concatenate() 方法,該方法的引數是要連接的兩個影像和要在哪個軸上進行堆疊,這里,我們令 axis = 1 (水平堆疊它們):
import numpy as np
img_concats = np.concatenate((img_OpenCV, img_matplotlib), axis=1)
cv2.imshow('bgr image and rgb image', img_concats)
cv2.waitKey(0)
cv2.destroyAllWindows()
下圖顯示了連接后的影像:
需要考慮的一個因素是 cv2.split() 是一項耗時的操作,如果確實需要劃分不同通道,應當首先考慮使用 NumPy 索引,例如,如果想獲取影像的一個通道,則可以使用 NumPy 索引獲取通道:
B = img_OpenCV[:, :, 0] G = img_OpenCV[:, :, 1] R = img_OpenCV[:, :, 2]
另一個需要注意的是,可以使用 NumPy 在一條陳述句中將影像從 BGR 轉換為 RGB:
img_matplotlib = img_OpenCV[:, :, ::-1]
在不同顏色空間中訪問和操作OpenCV中的像素
本節將介紹如何使用 OpenCV 訪問和讀取像素值以及如何修改它們,此外,還將學習如何訪問影像屬性,如果想一次處理多個像素,則需要創建影像區域 (Region of Image, ROI),
在 Python 中,影像表示為 NumPy 陣列,因此,示例中包含的大多數操作都與 NumPy 相關,建議需要對 NumPy 包一些了解,才能更好明白示例代碼的原理,但即使不了解也沒關系,必要時會對所用函式進行講解,
彩色影像訪問和操作OpenCV中的像素
現在,我們來看看如何在 OpenCV 中處理BGR影像,如上所述,OpenCV 加載彩色影像時,藍色通道是第一個,綠色通道是第二個,紅色通道是第三個,
首先,使用 cv2.imread() 函式讀取影像,影像應該在作業目錄中,或者應該提供圖片的完整路徑,在本例中,讀取 sigonghuiye.jpeg影像并將其存盤在img變數中:
img = cv2.imread('sigonghuiye.jpeg')
影像加載到 img 后,可以獲得影像的一些屬性,我們要從加載的影像中提取的第一個屬性是 shape,它將告訴我們行、列和通道的數量(如果影像是彩色的),我們將此資訊存盤在 dimensions 變數中:
dimensions = img.shape
第二個屬性是影像的大小(img.size=影像高度 × 影像寬度 × 影像通道數):
total_number_of_elements= img.size
第三個屬性是影像資料型別,可以通過 img.dtype 獲得,因為像素值在 [0-255] 范圍內,所以影像資料型別是 uint8 (unsigned char):
image_dtype = img.dtype上面示例中,我們已經使用了 cv2.imshow() 函式來在視窗中顯示影像,這里我們對其進行更詳細的介紹,使用 cv2.imshow() 函式顯示影像時,視窗會自動適應影像大小,此函式的第一個引數是視窗名,第二個引數是要顯示的影像,在這種情況下,由于加載的影像已存盤在 img 變數中,因此使用此變數作為第二個引數:
cv2.imshow("original image", img)
OpenCV影像處理基礎小結 在本文中,首先介紹了與影像相關的關鍵概念,影像構成了構建計算機視覺專案所必需的豐富資訊,然后,我們需要了解 OpenCV 使用 BGR 顏色格式而不是 RGB,但有一些 Python 包(例如 Matplotlib )使用后一種格式,因此,需要了解如何將影像從一種顏色格式轉換為另一種顏色格式, 此外,還總結了處理影像的主要函式和引數: 訪問影像屬性 OpenCV 常用函式,例如 cv2.imread() 、 cv2.split() 、 cv2.merge() 、 cv2.imshow() 、 cv2.waitKey() 和 cv2.destroyAllWindows() 如何在 BGR 和灰度影像中獲取和操作影像像素
⑥專案原始碼案例分享有
如果你用得到的話可以直接拿走,在我的QQ技術交流群里群號:948351247(純技術交流和資源共享,廣告勿入)以自助拿走
原始碼獲取點擊這里
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/294316.html
標籤:其他
