作者:Anirudh Rao
翻譯:吳金笛
校對:李潔
本文約4000字,建議閱讀10+分鐘。
本文將通過幾個簡單的實例帶你上手OpenCV庫,新手必備!
OpenCV Python 教程
在這個OpenCV Python 的教程中, 我們將使用Python中的OpenCV庫來介紹計算機視覺的各個方面。OpenCV 長期以來一直是軟體開發的重要部分。對開發人員來說學習OpenCV是提高編程能力並幫助他們發展軟體開發職業生涯的好方法。
什麼是計算機視覺?
為了簡化這個問題的答案, 讓我們來試想一個場景。
假設你和你的朋友去度假,然後你上傳了很多照片到Facebook上。但是現在在每張照片中找到你朋友的臉並標記它們要花費很多時間。實際上,Facebook已經足夠智能,它可以幫你標記人物。
那麼,你認為自動的特徵標記是如何工作的呢? 簡單來說,它通過計算機視覺來實現。
計算機視覺是一個跨學科領域,它解決如何使計算機從數字圖像或視頻中獲得高層次的理解的問題。
這裡的想法是將人類視覺系統可以完成的任務自動化。因此,計算機應該能夠識別諸如人臉或者燈柱甚至雕像之類的物體。
計算機如何讀取圖像?
思考以下圖片:
我們可以認出它是紐約天際線的圖片。 但是計算機可以自己發現這一切嗎?答案是不!
計算機將任何圖片都讀取為一組0到255之間的值。
對於任何一張彩色圖片,有三個主通道——紅色(R),綠色(G)和藍色(B)。它的工作原理非常簡單。
對每個原色創建一個矩陣,然後,組合這些矩陣以提供R, G和B各個顏色的像素值。
每一個矩陣的元素提供與像素的亮度強度有關的數據。
思考下圖:
如圖所示,圖像的大小被計算為B x A x 3。
注意:對於黑白圖片,只有一個單一通道。
現在讓我們來看看OpenCV究竟是什麼。
什麼是OpenCV?
OpenCV是一個旨在解決計算機視覺問題的Python庫。OpenCV最初由Intel在1999年開發,但是後來由Willow Garage資助。它支持很多程式語言,如C++,Python,Java等等。它也支持多種平臺,包括Windows,Linux和MacOS。
OpenCV Python只是一個與Python一起使用的原始C++庫的包裝類。通過使用它,所有OpenCV數組結構都能被轉化為NumPy數組或從NumPy數組轉化而來。這樣就可以輕鬆地將其與其他使用NumPy的庫集成。例如,SciPy和Matplotlib等庫。
OpenCV的基礎操作?
Opencv能完成以下從加載圖像到調整大小等基本操作:
使用OpenCV加載圖片
查看圖片形狀/解析度
顯示圖片
調整圖像大小
1. 使用OpenCV加載圖片
Import cv2
# colored Image
Img = cv2.imread ("Penguins.jpg",1)
# Black and White (gray scale)
Img_1 = cv2.imread ("Penguins.jpg",0)
如以上代碼所示,第一個要求是導入OpenCV模塊。
之後,我們可以用imread模塊讀取圖片。參數中的1代表這是一個彩色圖片。如果這個參數的值是0,就意味著這個將被導入的圖片是黑白圖片。這裡的圖片名稱是「Penguins」。很簡單吧?
2. 查看圖片形狀/解析度
我們可以使用shape子函數來輸出圖片的形狀。看看以下代碼:
Import cv2
# Black and White (gray scale)
Img = cv2.imread ("Penguins.jpg",0)
Print(img.shape)
對於圖片的形狀,我們指的是NumPy數組的形狀。執行代碼之後你將會看到這個矩陣由768行和1024列組成。
3. 顯示圖片
使用OpenCV顯示圖片非常簡單和直接。思考以下圖片:
import cv2
# Black and White (gray scale)
Img = cv2.imread ("Penguins.jpg",0)
cv2.imshow("Penguins", img)
cv2.waitKey(0)
# cv2.waitKey(2000)
cv2.destroyAllWindows()
正如你所見,我們首先使用imread導入圖片。我們需要一個輸出窗口來顯示這個圖片,對吧?
然後,我們等待用戶事件。waitKey使窗口保持靜態直到用戶按下一個鍵。傳入的參數是以毫秒為單位的時間。
最後,我們根據waitForKey的參數使用destroyAllWindows關閉窗口。
4. 調整圖像大小
類似地,調整圖像大小非常簡單。 這裡有另一個代碼段:
import cv2
# Black and White (gray scale)
img = cv2.imread ("Penguins.jpg",0)
resized_image = cv2.resize(img, (650,500))
cv2.imshow("Penguins", resized_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
這裡,resize函數用於將圖像大小調整為所需的形狀。這裡的參數是新調整大小後的圖像的形狀。
與之前的代碼相比,剩下的代碼非常簡單,對嗎?
我相信你們對企鵝很好奇,這是我們想要輸出的圖片!
這是另一個向resize函數傳遞參數的方法。看看下面的表示方法:
Resized_image = cv2.resize(img, int(img.shape[1]/2), int(img.shape[0]/2)))
這裡,我們得到的新圖像大小是原始圖像的一半。
使用OpenCV進行人臉檢測
這看起來很複雜,但實際上很容易。 讓我帶你了解整個過程,然後你也會有同樣的感受。
第一步:想一想我們的先決條件。我們首先需要一個圖像。然後,我們需要創建一個級聯分類器,它最後會給我們提供面部特徵。
第二步:這一步要使用到OpenCV讀取圖像和特徵文件。所以這個時候,原始數據點是NumPy數組的形式。
我們要做的就是搜索麵部 NumPy n維數組的行和列的值。這是具有面部矩形坐標的數組。
第三步:最後一步是使用矩形面框顯示圖像。
看看下面的圖片,這裡我以圖片的形式總結了上述的三個步驟以便於閱讀:
非常直接明了,對吧?
首先,如之前所述,我們創建CascadeClassifier對象來提取面部特徵。包含面部特徵的XML文件路徑是此處的參數。
下一步是讀取一個包含面部的圖片,並且使用COLOR_BGR2GREY將其轉化為黑白圖片。接下來,我們搜索圖像的坐標。這是使用detectMultiScale來實現的。
你問什麼坐標?它是面部矩形的坐標。scaleFactor被用來減小5%的形狀值,直到找到面部。因此,總的來說,值越小,準確度越高。
最後,這張臉被顯示到窗口。
這個邏輯很簡單——就像使用for循環語句一樣簡單。看看下面的圖片:
我們通過傳遞參數(比如圖片對象,輪廓框的RGB值和矩形的寬度),使用cv2.rectangle來定義方法以創建一個矩形。
讓我們來看看面部檢測的完整代碼:
import cv2
# Create a CascadeClassifier Object
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
# Reading the image as it is
img = cv2.imread("photo.jpg")
# Reading the image as gray scale image
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Search the co-ordintes of the image
faces = face_cascade.detectMultiScale(gray_img, scaleFactor = 1.05, minNeighbors=5)
for x,y,w,h in faces:
img = cv2.rectangle(img, (x,y), (x+w,y+h),(0,255,0),3)
resized = cv2.resize(img, (int(img.shape[1]/7),int(img.shape[0]/7)))
cv2.imshow("Gray", resized)
cv2.waitKey(0)
cv2.destroyAllWindows()
使用OpenCV捕獲視頻
使用OpenCV捕獲視頻同樣非常簡單。以下的流程能夠給你一個更好的理解。看看這個:
圖片被逐個讀取,因此由於幀的快速處理而產生視頻,這使得獨立的圖片動起來。
看一看下面這張圖:
首先我們像平常一樣導入OpenCV庫。接下來,我們有一個叫做VideoCapture的方法,用來創建VideoCapture對象。這個方法用於觸發用戶計算機上的攝像頭。這個函數的參數表示程序應該使用內置攝像頭還是附加攝像頭。「0」表示在這個例子中使用內置攝像頭。
最後,release方法用於在幾毫秒內釋放攝像頭。
當你繼續並嘗試執行上述代碼時,你會注意到攝像頭指示燈會在一瞬間開啟並稍後關閉。為什麼會這樣?
這是因為沒有持續時間來保持相機功能。
看看以上代碼,我們有新的一行time.sleep(3)。這使腳本停止3秒。請注意,傳遞的參數是以秒為單位的時間。因此,當代碼執行時,網絡攝像頭將開啟3秒鐘。
添加一個窗口來顯示視頻的輸出非常簡單,與用於圖像的相同方法差不多。 但是,還是有一點變化。 請看以下代碼:
我很確定除了一兩行外,你能很大程度地理解以上的代碼。
在這裡,我們定義了一個NumPy數組,用於表示視頻捕獲的第一個圖像。它被保存在frame數組中。
我們還有check。這是一個布爾數據類型。如果Python能夠訪問和讀取VideoCapture對象則返回True。
看看下面的輸出:
如你所見,我們得到的輸出為True,並列印了frame數組的一部分。
但是我們需要讀取視頻的第一個幀/圖才能開始,是吧?
要做到這一點,首先我們需要創建一個frame對象,它將讀取VideoCapture對象的圖像。
如上所示,imshow方法用於捕獲視頻的第一幀。
在此期間,我們已經嘗試了捕獲視頻的第一圖像/幀。
那麼我們如何在OpenCV中捕獲視頻而不是第一張圖像呢?
為了捕獲視頻,我們將使用while循環。while的條件是這樣的:除非「check」值為True,否則Python將顯示幀。
這是代碼段的圖片:
我們利用cvtColor函數將每個幀轉換為灰度圖像,如前所述。
waitKey(1)將確保在每毫秒的間隙後生成一個新幀。
重要的是要注意while循環是完全有效的,以幫助完全迭代幀並在最終顯示視頻。
這裡還有一個用戶事件觸發器。一旦用戶按下「q」鍵,程序窗口就會關閉。
OpenCV很容易掌握,對吧? 我個人喜歡它的良好的可讀性以及初學者開始使用OpenCV時極快的上手速度。
使用案例:使用OpenCV的運動檢測器
1. 問題描述
你正在接觸一家研究人類行為的公司。你的任務是為他們提供可以檢測前方運動的網絡攝像頭。它應該返回一個圖,並且這個圖應該包含人/物體在攝像頭前面的時間。
那麼現在我們已經定義了我們的問題陳述,我們需要構建一個解決方案邏輯以結構化的方式來解決問題。
看看下面的圖表:
最開始,我們將圖像保存在特定的frame當中。
下一步是將圖像轉化為高斯模糊圖像。這樣做是為了保證我們能計算模糊圖像和真實圖像之間的明顯的差異。
此時,圖像仍然不是對象。我們定義一個閾值來去除瑕疵,比如圖像中的陰影和其他噪聲。
對象的邊框稍後定義。我們在對象周圍添加一個矩形框,正如我們在本教程前面所討論的那樣。
最後,我們計算對象出現在畫面和退出畫面的時間。
很簡單吧?
這是代碼段:
這裡也遵循同樣的原則。我們首先導入包並創建VideoCapture對象,以確保我們使用網絡攝像頭捕獲視頻。
While循環遍歷視頻的各個幀。我們將彩色幀轉換為灰度圖像,然後將此灰度圖像轉化為高斯模糊圖。
我們需要存儲視頻的第一個圖像/幀,對吧?出於這個目的,我們使用if語句。
現在,讓我們深入了解一下代碼:
我們使用absdiff函數計算第一個幀和其他所有幀之間的差異。
threshold函數提供閾值,它將差異值小於30的像素轉換為黑。如果像素的差異值大於30,則轉換為白色。THRESH_BINARY就適用於此目的。
然後,我們使用findContours函數給圖像定義輪廓區域。我們也在這個階段加入邊界。
就像之前解釋過的,contourArea函數可消除陰影和噪聲。為了簡化,它將只保留白色部分,正如我們定義的,白色部分面積大於1000像素。
然後,在我們的工作幀中在對象的周圍創建一個矩形框。
接下來是這個簡單的代碼:
如前所述,幀每毫秒改變一次,並且當用戶輸入「q」時,跳出循環並關閉窗口。
在我們的用例中還有一件事就是我們要計算對象在攝像頭前的時間。
2. 計算時間
我們用DataFrame存儲對象出現在幀中被檢測到的時間和運動的時間。
接下來是我們之前解釋過的VideoCapture函數。但是在這裡,我們有一個標誌位,稱之為status。我們在記錄開始時設置status為0,因為對象在最初是不可見的。
如上圖所示,當檢測到對象時,我們將status標誌更改為1。很簡單吧?
我們將創建一個status的列表存儲每一個掃描到的幀的狀態,然後如果某處發生改變則使用datetime在列表中記錄日期和時間。
如以上的解釋圖所示,我們將時間值存儲在 DataFrame中。我們以把DataFrame寫入CSV文件中結束,如圖所示。
3. 繪製運動檢測圖
我們實例的最後一步是顯示結果。我們將要顯示的是表示兩軸上的運動的圖形。看看以下代碼:
首先,我們從motion_detector.py文件中導入DataFrame。
下一步是將時間轉換為可讀的並且可以解析的字符串形式。
最後,使用Bokeh plots在瀏覽器上繪製時間值的DataFrame。
輸出:
結論:
我希望這個OpenCV Python的教程能幫助你學習所有由Python開始使用OpenCV所需的基礎。
當你嘗試開發需要圖像識別和類似原理的軟體時就會非常方便了。現在你還能夠在Python OpenCV的幫助下輕鬆地使用這些概念來開發應用程式。
原文標題:
Computer Vision Using OpenCV
原文連結:
https://dzone.com/articles/opencv-python-tutorial-computer-vision-using-openc
吳金笛,雪城大學計算機科學碩士一年級在讀。迎難而上是我最舒服的狀態,動心忍性,曾益我所不能。我的目標是做個早睡早起的Cool Girl。
工作內容:需要一顆細緻的心,將選取好的外文文章翻譯成流暢的中文。如果你是數據科學/統計學/計算機類的留學生,或在海外從事相關工作,或對自己外語水平有信心的朋友歡迎加入翻譯小組。
你能得到:定期的翻譯培訓提高志願者的翻譯水平,提高對於數據科學前沿的認知,海外的朋友可以和國內技術應用發展保持聯繫,THU數據派產學研的背景為志願者帶來好的發展機遇。
其他福利:來自於名企的數據科學工作者,北大清華以及海外等名校學生他們都將成為你在翻譯小組的夥伴。
點擊文末「閱讀原文」加入數據派團隊~
點擊「閱讀原文」擁抱組織