作者:Anirudh Rao
翻譯:吳金笛
校對(duì):李潔
本文約4000字,建議閱讀10 分鐘。
本文將通過(guò)幾個(gè)簡(jiǎn)單的實(shí)例帶你上手OpenCV庫(kù),新手必備!
OpenCV Python 教程
在這個(gè)OpenCV Python 的教程中, 我們將使用Python中的OpenCV庫(kù)來(lái)介紹計(jì)算機(jī)視覺(jué)的各個(gè)方面。OpenCV 長(zhǎng)期以來(lái)一直是軟件開(kāi)發(fā)的重要部分。對(duì)開(kāi)發(fā)人員來(lái)說(shuō)學(xué)習(xí)OpenCV是提高編程能力并幫助他們發(fā)展軟件開(kāi)發(fā)職業(yè)生涯的好方法。
什么是計(jì)算機(jī)視覺(jué)?
為了簡(jiǎn)化這個(gè)問(wèn)題的答案, 讓我們來(lái)試想一個(gè)場(chǎng)景。
假設(shè)你和你的朋友去度假,然后你上傳了很多照片到Facebook上。但是現(xiàn)在在每張照片中找到你朋友的臉并標(biāo)記它們要花費(fèi)很多時(shí)間。實(shí)際上,F(xiàn)acebook已經(jīng)足夠智能,它可以幫你標(biāo)記人物。
那么,你認(rèn)為自動(dòng)的特征標(biāo)記是如何工作的呢? 簡(jiǎn)單來(lái)說(shuō),它通過(guò)計(jì)算機(jī)視覺(jué)來(lái)實(shí)現(xiàn)。
計(jì)算機(jī)視覺(jué)是一個(gè)跨學(xué)科領(lǐng)域,它解決如何使計(jì)算機(jī)從數(shù)字圖像或視頻中獲得高層次的理解的問(wèn)題。
這里的想法是將人類視覺(jué)系統(tǒng)可以完成的任務(wù)自動(dòng)化。因此,計(jì)算機(jī)應(yīng)該能夠識(shí)別諸如人臉或者燈柱甚至雕像之類的物體。
計(jì)算機(jī)如何讀取圖像?
思考以下圖片:
我們可以認(rèn)出它是紐約天際線的圖片。 但是計(jì)算機(jī)可以自己發(fā)現(xiàn)這一切嗎?答案是不!
計(jì)算機(jī)將任何圖片都讀取為一組0到255之間的值。
對(duì)于任何一張彩色圖片,有三個(gè)主通道——紅色(R),綠色(G)和藍(lán)色(B)。它的工作原理非常簡(jiǎn)單。
對(duì)每個(gè)原色創(chuàng)建一個(gè)矩陣,然后,組合這些矩陣以提供R, G和B各個(gè)顏色的像素值。
每一個(gè)矩陣的元素提供與像素的亮度強(qiáng)度有關(guān)的數(shù)據(jù)。
思考下圖:
如圖所示,圖像的大小被計(jì)算為B x A x 3。
注意:對(duì)于黑白圖片,只有一個(gè)單一通道。
現(xiàn)在讓我們來(lái)看看OpenCV究竟是什么。
什么是OpenCV?
OpenCV是一個(gè)旨在解決計(jì)算機(jī)視覺(jué)問(wèn)題的Python庫(kù)。OpenCV最初由Intel在1999年開(kāi)發(fā),但是后來(lái)由Willow Garage資助。它支持很多編程語(yǔ)言,如C ,Python,Java等等。它也支持多種平臺(tái),包括Windows,Linux和MacOS。
OpenCV Python只是一個(gè)與Python一起使用的原始C 庫(kù)的包裝類。通過(guò)使用它,所有OpenCV數(shù)組結(jié)構(gòu)都能被轉(zhuǎn)化為NumPy數(shù)組或從NumPy數(shù)組轉(zhuǎn)化而來(lái)。這樣就可以輕松地將其與其他使用NumPy的庫(kù)集成。例如,SciPy和Matplotlib等庫(kù)。
OpenCV的基礎(chǔ)操作?
Opencv能完成以下從加載圖像到調(diào)整大小等基本操作:
- 使用OpenCV加載圖片
- 查看圖片形狀/分辨率
- 顯示圖片
- 調(diào)整圖像大小
1. 使用OpenCV加載圖片
Import cv2 # colored Image Img = cv2.imread (\”Penguins.jpg\”,1) # Black and White (gray scale) Img_1 = cv2.imread (\”Penguins.jpg\”,0)
如以上代碼所示,第一個(gè)要求是導(dǎo)入OpenCV模塊。
之后,我們可以用imread模塊讀取圖片。參數(shù)中的1代表這是一個(gè)彩色圖片。如果這個(gè)參數(shù)的值是0,就意味著這個(gè)將被導(dǎo)入的圖片是黑白圖片。這里的圖片名稱是“Penguins”。很簡(jiǎn)單吧?
2. 查看圖片形狀/分辨率
我們可以使用shape子函數(shù)來(lái)輸出圖片的形狀。看看以下代碼:
Import cv2 # Black and White (gray scale) Img = cv2.imread (\”Penguins.jpg\”,0) Print(img.shape)
對(duì)于圖片的形狀,我們指的是NumPy數(shù)組的形狀。執(zhí)行代碼之后你將會(huì)看到這個(gè)矩陣由768行和1024列組成。
3. 顯示圖片
使用OpenCV顯示圖片非常簡(jiǎn)單和直接。思考以下圖片:
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()
正如你所見(jiàn),我們首先使用imread導(dǎo)入圖片。我們需要一個(gè)輸出窗口來(lái)顯示這個(gè)圖片,對(duì)吧?
然后,我們等待用戶事件。waitKey使窗口保持靜態(tài)直到用戶按下一個(gè)鍵。傳入的參數(shù)是以毫秒為單位的時(shí)間。
最后,我們根據(jù)waitForKey的參數(shù)使用destroyAllWindows關(guān)閉窗口。
4. 調(diào)整圖像大小
類似地,調(diào)整圖像大小非常簡(jiǎn)單。 這里有另一個(gè)代碼段:
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函數(shù)用于將圖像大小調(diào)整為所需的形狀。這里的參數(shù)是新調(diào)整大小后的圖像的形狀。
與之前的代碼相比,剩下的代碼非常簡(jiǎn)單,對(duì)嗎?
我相信你們對(duì)企鵝很好奇,這是我們想要輸出的圖片!
這是另一個(gè)向resize函數(shù)傳遞參數(shù)的方法。看看下面的表示方法:
Resized_image = cv2.resize(img, int(img.shape[1]/2), int(img.shape[0]/2)))
這里,我們得到的新圖像大小是原始圖像的一半。
使用OpenCV進(jìn)行人臉檢測(cè)
這看起來(lái)很復(fù)雜,但實(shí)際上很容易。 讓我?guī)懔私庹麄€(gè)過(guò)程,然后你也會(huì)有同樣的感受。
第一步:想一想我們的先決條件。我們首先需要一個(gè)圖像。然后,我們需要?jiǎng)?chuàng)建一個(gè)級(jí)聯(lián)分類器,它最后會(huì)給我們提供面部特征。
第二步:這一步要使用到OpenCV讀取圖像和特征文件。所以這個(gè)時(shí)候,原始數(shù)據(jù)點(diǎn)是NumPy數(shù)組的形式。
我們要做的就是搜索面部 NumPy n維數(shù)組的行和列的值。這是具有面部矩形坐標(biāo)的數(shù)組。
第三步:最后一步是使用矩形面框顯示圖像。
看看下面的圖片,這里我以圖片的形式總結(jié)了上述的三個(gè)步驟以便于閱讀:
非常直接明了,對(duì)吧?
首先,如之前所述,我們創(chuàng)建CascadeClassifier對(duì)象來(lái)提取面部特征。包含面部特征的XML文件路徑是此處的參數(shù)。
下一步是讀取一個(gè)包含面部的圖片,并且使用COLOR_BGR2GREY將其轉(zhuǎn)化為黑白圖片。接下來(lái),我們搜索圖像的坐標(biāo)。這是使用detectMultiScale來(lái)實(shí)現(xiàn)的。
你問(wèn)什么坐標(biāo)?它是面部矩形的坐標(biāo)。scaleFactor被用來(lái)減小5%的形狀值,直到找到面部。因此,總的來(lái)說(shuō),值越小,準(zhǔn)確度越高。
最后,這張臉被顯示到窗口。
- 給識(shí)別的人臉添加矩形面框
這個(gè)邏輯很簡(jiǎn)單——就像使用for循環(huán)語(yǔ)句一樣簡(jiǎn)單??纯聪旅娴膱D片:
我們通過(guò)傳遞參數(shù)(比如圖片對(duì)象,輪廓框的RGB值和矩形的寬度),使用cv2.rectangle來(lái)定義方法以創(chuàng)建一個(gè)矩形。
讓我們來(lái)看看面部檢測(cè)的完整代碼:
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捕獲視頻同樣非常簡(jiǎn)單。以下的流程能夠給你一個(gè)更好的理解。看看這個(gè):
圖片被逐個(gè)讀取,因此由于幀的快速處理而產(chǎn)生視頻,這使得獨(dú)立的圖片動(dòng)起來(lái)。
看一看下面這張圖:
首先我們像平常一樣導(dǎo)入OpenCV庫(kù)。接下來(lái),我們有一個(gè)叫做VideoCapture的方法,用來(lái)創(chuàng)建VideoCapture對(duì)象。這個(gè)方法用于觸發(fā)用戶計(jì)算機(jī)上的攝像頭。這個(gè)函數(shù)的參數(shù)表示程序應(yīng)該使用內(nèi)置攝像頭還是附加攝像頭?!?”表示在這個(gè)例子中使用內(nèi)置攝像頭。
最后,release方法用于在幾毫秒內(nèi)釋放攝像頭。
當(dāng)你繼續(xù)并嘗試執(zhí)行上述代碼時(shí),你會(huì)注意到攝像頭指示燈會(huì)在一瞬間開(kāi)啟并稍后關(guān)閉。為什么會(huì)這樣?
這是因?yàn)闆](méi)有持續(xù)時(shí)間來(lái)保持相機(jī)功能。
看看以上代碼,我們有新的一行time.sleep(3)。這使腳本停止3秒。請(qǐng)注意,傳遞的參數(shù)是以秒為單位的時(shí)間。因此,當(dāng)代碼執(zhí)行時(shí),網(wǎng)絡(luò)攝像頭將開(kāi)啟3秒鐘。
- 添加窗口
添加一個(gè)窗口來(lái)顯示視頻的輸出非常簡(jiǎn)單,與用于圖像的相同方法差不多。 但是,還是有一點(diǎn)變化。 請(qǐng)看以下代碼:
我很確定除了一兩行外,你能很大程度地理解以上的代碼。
在這里,我們定義了一個(gè)NumPy數(shù)組,用于表示視頻捕獲的第一個(gè)圖像。它被保存在frame數(shù)組中。
我們還有check。這是一個(gè)布爾數(shù)據(jù)類型。如果Python能夠訪問(wèn)和讀取VideoCapture對(duì)象則返回True。
看看下面的輸出:
如你所見(jiàn),我們得到的輸出為True,并打印了frame數(shù)組的一部分。
但是我們需要讀取視頻的第一個(gè)幀/圖才能開(kāi)始,是吧?
要做到這一點(diǎn),首先我們需要?jiǎng)?chuàng)建一個(gè)frame對(duì)象,它將讀取VideoCapture對(duì)象的圖像。
如上所示,imshow方法用于捕獲視頻的第一幀。
在此期間,我們已經(jīng)嘗試了捕獲視頻的第一圖像/幀。
那么我們?nèi)绾卧贠penCV中捕獲視頻而不是第一張圖像呢?
- 直接捕獲視頻
為了捕獲視頻,我們將使用while循環(huán)。while的條件是這樣的:除非“check”值為True,否則Python將顯示幀。
這是代碼段的圖片:
我們利用cvtColor函數(shù)將每個(gè)幀轉(zhuǎn)換為灰度圖像,如前所述。
waitKey(1)將確保在每毫秒的間隙后生成一個(gè)新幀。
重要的是要注意while循環(huán)是完全有效的,以幫助完全迭代幀并在最終顯示視頻。
這里還有一個(gè)用戶事件觸發(fā)器。一旦用戶按下“q”鍵,程序窗口就會(huì)關(guān)閉。
OpenCV很容易掌握,對(duì)吧? 我個(gè)人喜歡它的良好的可讀性以及初學(xué)者開(kāi)始使用OpenCV時(shí)極快的上手速度。
使用案例:使用OpenCV的運(yùn)動(dòng)檢測(cè)器
1. 問(wèn)題描述
你正在接觸一家研究人類行為的公司。你的任務(wù)是為他們提供可以檢測(cè)前方運(yùn)動(dòng)的網(wǎng)絡(luò)攝像頭。它應(yīng)該返回一個(gè)圖,并且這個(gè)圖應(yīng)該包含人/物體在攝像頭前面的時(shí)間。
那么現(xiàn)在我們已經(jīng)定義了我們的問(wèn)題陳述,我們需要構(gòu)建一個(gè)解決方案邏輯以結(jié)構(gòu)化的方式來(lái)解決問(wèn)題。
看看下面的圖表:
最開(kāi)始,我們將圖像保存在特定的frame當(dāng)中。
下一步是將圖像轉(zhuǎn)化為高斯模糊圖像。這樣做是為了保證我們能計(jì)算模糊圖像和真實(shí)圖像之間的明顯的差異。
此時(shí),圖像仍然不是對(duì)象。我們定義一個(gè)閾值來(lái)去除瑕疵,比如圖像中的陰影和其他噪聲。
對(duì)象的邊框稍后定義。我們?cè)趯?duì)象周圍添加一個(gè)矩形框,正如我們?cè)诒窘坛糖懊嫠懻摰哪菢印?/p>
最后,我們計(jì)算對(duì)象出現(xiàn)在畫(huà)面和退出畫(huà)面的時(shí)間。
很簡(jiǎn)單吧?
這是代碼段:
這里也遵循同樣的原則。我們首先導(dǎo)入包并創(chuàng)建VideoCapture對(duì)象,以確保我們使用網(wǎng)絡(luò)攝像頭捕獲視頻。
While循環(huán)遍歷視頻的各個(gè)幀。我們將彩色幀轉(zhuǎn)換為灰度圖像,然后將此灰度圖像轉(zhuǎn)化為高斯模糊圖。
我們需要存儲(chǔ)視頻的第一個(gè)圖像/幀,對(duì)吧?出于這個(gè)目的,我們使用if語(yǔ)句。
現(xiàn)在,讓我們深入了解一下代碼:
我們使用absdiff函數(shù)計(jì)算第一個(gè)幀和其他所有幀之間的差異。
threshold函數(shù)提供閾值,它將差異值小于30的像素轉(zhuǎn)換為黑。如果像素的差異值大于30,則轉(zhuǎn)換為白色。THRESH_BINARY就適用于此目的。
然后,我們使用findContours函數(shù)給圖像定義輪廓區(qū)域。我們也在這個(gè)階段加入邊界。
就像之前解釋過(guò)的,contourArea函數(shù)可消除陰影和噪聲。為了簡(jiǎn)化,它將只保留白色部分,正如我們定義的,白色部分面積大于1000像素。
然后,在我們的工作幀中在對(duì)象的周圍創(chuàng)建一個(gè)矩形框。
接下來(lái)是這個(gè)簡(jiǎn)單的代碼:
如前所述,幀每毫秒改變一次,并且當(dāng)用戶輸入“q”時(shí),跳出循環(huán)并關(guān)閉窗口。
在我們的用例中還有一件事就是我們要計(jì)算對(duì)象在攝像頭前的時(shí)間。
2. 計(jì)算時(shí)間
我們用DataFrame存儲(chǔ)對(duì)象出現(xiàn)在幀中被檢測(cè)到的時(shí)間和運(yùn)動(dòng)的時(shí)間。
接下來(lái)是我們之前解釋過(guò)的VideoCapture函數(shù)。但是在這里,我們有一個(gè)標(biāo)志位,稱之為status。我們?cè)谟涗涢_(kāi)始時(shí)設(shè)置status為0,因?yàn)閷?duì)象在最初是不可見(jiàn)的。
如上圖所示,當(dāng)檢測(cè)到對(duì)象時(shí),我們將status標(biāo)志更改為1。很簡(jiǎn)單吧?
我們將創(chuàng)建一個(gè)status的列表存儲(chǔ)每一個(gè)掃描到的幀的狀態(tài),然后如果某處發(fā)生改變則使用datetime在列表中記錄日期和時(shí)間。
如以上的解釋圖所示,我們將時(shí)間值存儲(chǔ)在 DataFrame中。我們以把DataFrame寫(xiě)入CSV文件中結(jié)束,如圖所示。
3. 繪制運(yùn)動(dòng)檢測(cè)圖
我們實(shí)例的最后一步是顯示結(jié)果。我們將要顯示的是表示兩軸上的運(yùn)動(dòng)的圖形??纯匆韵麓a:
首先,我們從motion_detector.py文件中導(dǎo)入DataFrame。
下一步是將時(shí)間轉(zhuǎn)換為可讀的并且可以解析的字符串形式。
最后,使用Bokeh plots在瀏覽器上繪制時(shí)間值的DataFrame。
輸出:
結(jié)論:
我希望這個(gè)OpenCV Python的教程能幫助你學(xué)習(xí)所有由Python開(kāi)始使用OpenCV所需的基礎(chǔ)。
當(dāng)你嘗試開(kāi)發(fā)需要圖像識(shí)別和類似原理的軟件時(shí)就會(huì)非常方便了。現(xiàn)在你還能夠在Python OpenCV的幫助下輕松地使用這些概念來(lái)開(kāi)發(fā)應(yīng)用程序。
原文標(biāo)題:
Computer Vision Using OpenCV
原文鏈接:
https://dzone.com/articles/opencv-python-tutorial-computer-vision-using-openc
譯者簡(jiǎn)介
吳金笛,雪城大學(xué)計(jì)算機(jī)科學(xué)碩士一年級(jí)在讀。迎難而上是我最舒服的狀態(tài),動(dòng)心忍性,曾益我所不能。我的目標(biāo)是做個(gè)早睡早起的Cool Girl。
— 完 —
關(guān)注清華-青島數(shù)據(jù)科學(xué)研究院官方微信公眾平臺(tái)“THU數(shù)據(jù)派”及姊妹號(hào)“數(shù)據(jù)派THU”獲取更多講座福利及優(yōu)質(zhì)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。