OpenCV是一款非常強大的圖像處理工具,對于從事圖像處理領(lǐng)域相關(guān)工作的人來說這個可以說是必不可少的一項工具,用起來也很方面,下嗎是一段簡單的介紹:
OpenCV是一個基于BSD許可(開源)發(fā)行的跨平臺計算機視覺和機器學(xué)習(xí)軟件庫,可以運行在Linux、Windows、Android和Mac OS操作系統(tǒng)上。它輕量級而且高效——由一系列 C 函數(shù)和少量 C++ 類構(gòu)成,同時提供了Python、Ruby、MATLAB等語言的接口,實現(xiàn)了圖像處理和計算機視覺方面的很多通用算法。OpenCV用C++語言編寫,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS,OpenCV主要傾向于實時視覺應(yīng)用,并在可用時利用MMX和SSE指令, 如今也提供對于C#、Ch、Ruby,GO的支持。
OpenCV官網(wǎng)是https://opencv.org/,首頁截圖如下所示:
下面給出來幾個學(xué)習(xí)OpenCV的鏈接:
https://docs.opencv.org/master/d9/df8/tutorial_root.html https://docs.opencv.org/ https://www.zhihu.com/question/26881367我們今天的內(nèi)容主要是想基于OpenCV來實現(xiàn)對圖像中我們關(guān)注的一些目標對象進行檢測識別或者說是對其存在的區(qū)域位置進行挖掘,在開始這篇文章之前,我曾經(jīng)看到了有人基于OpenCV實現(xiàn)了火焰或者是煙霧的檢測,其實不管是類似的物體的檢測也好不相關(guān)的物體識別檢測也好,很大程度是比較通用的做法都是基于像素來完成最終的計算的。 這里我們以生活中最為常見的土地來作為要識別檢測的目標對象進行實驗,先來看一張網(wǎng)上找到的圖片,如下所示:
接下來先看一下,最終的識別檢測效果:
從上面的結(jié)果來看,比較完全地檢測到了圖中出現(xiàn)的土地的區(qū)域,最終,我們采用外切矩形的方式完成了對其輪廓數(shù)據(jù)的確定。 接下來,我們進入正文,在實際去實踐之前,我們很有必要來了解一下幾種比較常用的顏色空間,簡單總結(jié)匯總?cè)缦拢?/p>
RGB顏色空間: R:Red紅色 G:Green綠色 B:Blue藍色 HSV顏色空間: H:Hue色度 S:Saturation飽和度 V:Value亮度 HSI顏色空間: H:Hue色度 S:Saturation飽和度 I:Intensity強度本質(zhì)上來講,不同的物體不同的對象自身的像素范圍是不同的,在實際操作的時候基于像素區(qū)間可以過濾得到你所關(guān)注的對象,通常這樣的操作會在HSV空間中進行,個人的理解是將原始的BGR或者是RGB的圖像轉(zhuǎn)化到HSV空間里面來確定目標對象的像素區(qū)間更為容易,我實際測試過,在RGB和BGR空間里面也是可以進行計算的,只不過不如HSV空間,這里就不再多討論了,可以嘗試別的方式,本文用的是HSV空間進行計算的。 最開始的時候去確定目標對象所處的像素空間是很笨拙的,主要是借助OpenCV和matplotlib實現(xiàn)的“人眼探索”,比較麻煩,后來在github社區(qū)里面找到了一個界面的實現(xiàn),覺得很不錯,就拿來用了,這里貼出來源碼實現(xiàn),如下所示:#!usr/bin/envpython #encoding:utf-8 from__future__importdivision ''' 功能:HSV空間圖片色素范圍查看器 ''' importcv2 importnumpyasnp defnothing(x): pass defcolorLooker(pic='1.png'): ''' HSV空間圖片色素范圍查看器 ''' #圖像加載 image=cv2.imread(pic) #窗口初始化 cv2.namedWindow('image',cv2.WINDOW_NORMAL) #創(chuàng)建拖動條 #Opencv中Hue取值范圍是0-179 cv2.createTrackbar('HMin','image',0,179,nothing) cv2.createTrackbar('SMin','image',0,255,nothing) cv2.createTrackbar('VMin','image',0,255,nothing) cv2.createTrackbar('HMax','image',0,179,nothing) cv2.createTrackbar('SMax','image',0,255,nothing) cv2.createTrackbar('VMax','image',0,255,nothing) #設(shè)置默認最大值 cv2.setTrackbarPos('HMax','image',179) cv2.setTrackbarPos('SMax','image',255) cv2.setTrackbarPos('VMax','image',255) #初始化設(shè)置 hMin=sMin=vMin=hMax=sMax=vMax=0 phMin=psMin=pvMin=phMax=psMax=pvMax=0 while(1): #實時獲取拖動條上的值 hMin=cv2.getTrackbarPos('HMin','image') sMin=cv2.getTrackbarPos('SMin','image') vMin=cv2.getTrackbarPos('VMin','image') hMax=cv2.getTrackbarPos('HMax','image') sMax=cv2.getTrackbarPos('SMax','image') vMax=cv2.getTrackbarPos('VMax','image') #設(shè)定HSV的最大和最小值 lower=np.array([hMin,sMin,vMin]) upper=np.array([hMax,sMax,vMax]) #BGR和HSV顏色空間轉(zhuǎn)化處理 hsv=cv2.cvtColor(image,cv2.COLOR_BGR2HSV) mask=cv2.inRange(hsv,lower,upper) result=cv2.bitwise_and(image,image,mask=mask) #拖動改變閾值的同時,實時輸出調(diào)整的信息 if((phMin!=hMin)|(psMin!=sMin)|(pvMin!=vMin)|(phMax!=hMax)|(psMax!=sMax)|(pvMax!=vMax)): print("(hMin=%d,sMin=%d,vMin=%d),(hMax=%d,sMax=%d,vMax=%d)"%(hMin,sMin,vMin,hMax,sMax,vMax)) phMin=hMin psMin=sMin pvMin=vMin phMax=hMax psMax=sMax pvMax=vMax #展示由色素帶閾值范圍處理過的結(jié)果圖片 cv2.imshow('image',result) ifcv2.waitKey(10)&0xFF==ord('q'): break cv2.destroyAllWindows() if__name__=='__main__': colorLooker(pic='1.png') 啟動后截圖如下所示:
借助界面中的拖動條可以很方便地進行調(diào)節(jié),看到實時處理后的結(jié)果圖片:
經(jīng)過調(diào)節(jié)后最終的結(jié)果如下所示:
調(diào)整拖動條的同時,終端窗口輸出如下所示:
到這里,我們已經(jīng)獲取到了所需要的各個維度的閾值數(shù)據(jù)了,就可以進行后面的處理了。 接下來我們基于上述閾值來進行區(qū)域挖掘計算,同樣使用上述的圖片,核心代碼實現(xiàn)如下所示:
img=Image.open('1.png') img=cv2.cvtColor(np.asarray(img),cv2.COLOR_RGB2BGR) frame=cv2.cvtColor(img,cv2.COLOR_BGR2HSV) blur=cv2.GaussianBlur(frame,(21,21),0) hsv=cv2.cvtColor(blur,cv2.COLOR_BGR2HSV) h,w,way=img.shape total=h*w print('h:',h,'w:',w,'area:',total) #設(shè)置閾值數(shù)據(jù) lower=[8,67,84] upper=[85,255,255] lower=np.array(lower,dtype="uint8") upper=np.array(upper,dtype="uint8") mask=cv2.inRange(hsv,lower,upper) output=cv2.bitwise_and(hsv,hsv,mask=mask) count=cv2.countNonZero(mask) print('count:',count) now_ratio=round(int(count)/total,3) print('now_ratio:',now_ratio)
之后為了得到實際的輪廓區(qū)域,我們可以使用cv2.findContours方法來實現(xiàn)目標對象的區(qū)域挖掘計算,核心代碼實現(xiàn)如下所示:gray=cv2.cvtColor(output,cv2.COLOR_BGR2GRAY) print('gray_shape:',gray.shape) ret,output=cv2.threshold(gray,127,255,cv2.THRESH_BINARY) ''' cv2.findContours:
在opencv中查找輪廓時,物體應(yīng)該是白色而背景應(yīng)該是黑色 contours,hierarchy=cv2.findContours(image,mode,method) image:輸入圖像 mode:輪廓的模式。cv2.RETR_EXTERNAL只檢測外輪廓;cv2.RETR_LIST檢測的輪廓不建立等級關(guān)系;cv2.RETR_CCOMP建立兩個等級的輪廓,上一層為外邊界,內(nèi)層為內(nèi)孔的邊界。如果內(nèi)孔內(nèi)還有連通物體,則這個物體的邊界也在頂層;cv2.RETR_TREE建立一個等級樹結(jié)構(gòu)的輪廓。 method:輪廓的近似方法。cv2.CHAIN_APPROX_NOME存儲所有的輪廓點,相鄰的兩個點的像素位置差不超過1;cv2.CHAIN_APPROX_SIMPLE壓縮水平方向、垂直方向、對角線方向的元素,只保留該方向的終點坐標,例如一個矩形輪廓只需要4個點來保存輪廓信息;cv2.CHAIN_APPROX_TC89_L1,cv2.CV_CHAIN_APPROX_TC89_KCOS contours:返回的輪廓 hierarchy:每條輪廓對應(yīng)的屬性 ''' contours,hierarchy=cv2.findContours(output,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) print('contours_num:',len(contours)) count_dict={} areas,lengths=0,0 foriinrange(len(contours)): one=contours[i] one_lk=one.tolist() iflen(one_lk)>=2: area=cv2.contourArea(one) length=cv2.arcLength(one,True) areas+=area lengths+=length left_list,right_list=[O[0][0]forOinone_lk],[O[0][1]forOinone_lk] minX,maxX,minY,maxY=min(left_list),max(left_list),min(right_list),max(right_list) A=abs(maxY-minY)*abs(maxX-minX) print('area:',area,'A:',A,'length:',length) count_dict[i]=[A,area,length,[minX,maxX,minY,maxY]] sorted_list=sorted(count_dict.items(),key=lambdae:e[1][0],reverse=True) print(sorted_list[:10]) result['value']=count_dict cv2.drawContours(img,contours,-1,(0,0,255),3)完成輪廓的挖掘計算后,我們借助于OpenCV實現(xiàn)可視化,結(jié)果如下所示:
可以看到:已經(jīng)大體上實現(xiàn)了我們所要的功能,但是美中不足的是里面有很多小的矩形框,這個是我們外切矩形設(shè)計的問題,沒有考慮到過濾掉嵌套或者是包含的情況,所以這里就來處理一下:
ifsorted_list: filter_list=filterBox(sorted_list[:5]) forone_boxinfilter_list: print('one_box:',one_box) A,area,length,[minX,maxX,minY,maxY]=one_box cv2.rectangle(img,(minX,maxY),(maxX,minY),(0,255,0),3)此時的結(jié)果如下所示:
對應(yīng)的計算結(jié)果輸出如下所示:
('h:',336L,'w:',500L,'area:',168000L) ('count:',126387) ('now_ratio:',0.752) ('output_shape:',(336L,500L,3L)) ('gray_shape:',(336L,500L)) ('contours_num:',64) ('area:',0.0,'A:',2,'length:',4.828427076339722) ('area:',0.0,'A:',0,'length:',4.0) ('area:',29.0,'A:',44,'length:',27.313708186149597) ('area:',42.5,'A:',72,'length:',34.72792184352875) ('area:',0.5,'A:',6,'length:',9.071067690849304) ('area:',0.0,'A:',10,'length:',11.656854152679443) ('area:',0.0,'A:',1,'length:',2.8284270763397217) ('area:',0.0,'A:',2,'length:',4.828427076339722) ('area:',1.5,'A:',2,'length:',5.414213538169861) ('area:',16.5,'A:',36,'length:',27.55634891986847) ('area:',5.0,'A:',36,'length:',37.79898953437805) ('area:',1.5,'A:',3,'length:',8.242640614509583) ('area:',0.0,'A:',0,'length:',2.0) ('area:',2.0,'A:',2,'length:',6.0) ('area:',360.0,'A:',1026,'length:',206.93607211112976) ('area:',44.0,'A:',143,'length:',59.94112479686737) ('area:',0.0,'A:',1,'length:',2.8284270763397217) ('area:',0.0,'A:',1,'length:',2.8284270763397217) ('area:',33.5,'A:',60,'length:',30.38477599620819) ('area:',76.5,'A:',228,'length:',63.35533845424652) ('area:',320.0,'A:',792,'length:',166.9949471950531) ('area:',16.0,'A:',35,'length:',21.313708305358887) ('area:',0.0,'A:',8,'length:',10.828427076339722) ('area:',21.0,'A:',78,'length:',37.79898953437805) ('area:',0.0,'A:',1,'length:',2.8284270763397217) ('area:',0.0,'A:',2,'length:',4.828427076339722) ('area:',0.0,'A:',2,'length:',4.828427076339722) ('area:',3.5,'A:',25,'length:',20.727921843528748) ('area:',1.5,'A:',12,'length:',13.071067690849304) ('area:',51.0,'A:',121,'length:',53.94112491607666) ('area:',0.0,'A:',1,'length:',2.8284270763397217) ('area:',32.5,'A:',50,'length:',27.899494767189026) ('area:',309.5,'A:',722,'length:',96.32590079307556) ('area:',34.0,'A:',42,'length:',22.485281229019165) ('area:',80970.5,'A:',132699,'length:',2718.5739262104034) [(63,[132699,80970.5,2718.5739262104034,[1,498,67,334]]),(24,[1026,360.0,206.93607211112976,[33,60,281,319]]),(39,[792,320.0,166.9949471950531,[61,94,252,276]]),(61,[722,309.5,96.32590079307556,[384,422,75,94]]),(34,[228,76.5,63.35533845424652,[1,13,267,286]]),(25,[143,44.0,59.94112479686737,[68,81,280,291]]),(55,[121,51.0,53.94112491607666,[189,200,219,230]]),(47,[78,21.0,37.79898953437805,[100,113,235,241]]),(4,[72,42.5,34.72792184352875,[209,221,328,334]]),(32,[60,33.5,30.38477599620819,[15,25,274,280]])] ('one_box:',[132699,80970.5,2718.5739262104034,[1,498,67,334]])為了更加直觀地對比分析,我們將上面計算各個步驟中的對象數(shù)據(jù)進行可視化,借助于matplotlib繪制在同一張圖上,結(jié)果如下所示:
左上角為原始圖片,右下角為最終處理得到的圖片,可以看到整個處理過程的變化。 到這里本文的內(nèi)容就結(jié)束了,學(xué)習(xí)依舊在路上,歡迎交流,互相學(xué)習(xí)!
作者:沂水寒城,CSDN博客專家,個人研究方向:機器學(xué)習(xí)、深度學(xué)習(xí)、NLP、CV
Blog:http://yishuihancheng.blog.csdn.net
責(zé)任編輯:PSY
原文標題:垃圾分類的正確姿勢?用 OpenCV 人工智能圖像識別技術(shù)來進行
文章出處:【微信公眾號:新機器視覺】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
-
圖像識別
+關(guān)注
關(guān)注
9文章
520瀏覽量
38273 -
檢測識別
+關(guān)注
關(guān)注
0文章
9瀏覽量
7237 -
OpenCV
+關(guān)注
關(guān)注
31文章
635瀏覽量
41352
原文標題:垃圾分類的正確姿勢?用 OpenCV 人工智能圖像識別技術(shù)來進行
文章出處:【微信號:vision263com,微信公眾號:新機器視覺】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論