<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          垃圾分類的正確姿勢?用 OpenCV 人工智能圖像識別技術(shù)來進(jìn)行

          共 9626字,需瀏覽 20分鐘

           ·

          2020-11-17 04:13

          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)注的一些目標(biāo)對象進(jìn)行檢測識別或者說是對其存在的區(qū)域位置進(jìn)行挖掘,在開始這篇文章之前,我曾經(jīng)看到了有人基于OpenCV實現(xiàn)了火焰或者是煙霧的檢測,其實不管是類似的物體的檢測也好不相關(guān)的物體識別檢測也好,很大程度是比較通用的做法都是基于像素來完成最終的計算的。
          這里我們以生活中最為常見的土地來作為要識別檢測的目標(biāo)對象進(jìn)行實驗,先來看一張網(wǎng)上找到的圖片,如下所示:

          接下來先看一下,最終的識別檢測效果:

          從上面的結(jié)果來看,比較完全地檢測到了圖中出現(xiàn)的土地的區(qū)域,最終,我們采用外切矩形的方式完成了對其輪廓數(shù)據(jù)的確定。
          接下來,我們進(jìn)入正文,在實際去實踐之前,我們很有必要來了解一下幾種比較常用的顏色空間,簡單總結(jié)匯總?cè)缦拢?/span>
          RGB顏色空間:
          R:Red?紅色
          G:Green?綠色
          B:Blue?藍(lán)色
          ?
          HSV顏色空間:
          H:Hue?色度
          S:Saturation?飽和度
          V:Value?亮度
          ?
          HSI顏色空間:
          H:Hue?色度
          S:Saturation?飽和度
          I:Intensity?強度
          本質(zhì)上來講,不同的物體不同的對象自身的像素范圍是不同的,在實際操作的時候基于像素區(qū)間可以過濾得到你所關(guān)注的對象,通常這樣的操作會在HSV空間中進(jìn)行,個人的理解是將原始的BGR或者是RGB的圖像轉(zhuǎn)化到HSV空間里面來確定目標(biāo)對象的像素區(qū)間更為容易,我實際測試過,在RGB和BGR空間里面也是可以進(jìn)行計算的,只不過不如HSV空間,這里就不再多討論了,可以嘗試別的方式,本文用的是HSV空間進(jìn)行計算的。
          最開始的時候去確定目標(biāo)對象所處的像素空間是很笨拙的,主要是借助OpenCV和matplotlib實現(xiàn)的“人眼探索”,比較麻煩,后來在github社區(qū)里面找到了一個界面的實現(xiàn),覺得很不錯,就拿來用了,這里貼出來源碼實現(xiàn),如下所示:
          #!usr/bin/env?python
          #?encoding:utf-8
          from?__future__?import?division
          ?
          '''
          功能:HSV空間圖片色素范圍查看器
          '''

          ?
          ?
          import?cv2
          import?numpy?as?np
          ?
          ?
          ?
          ?
          def?nothing(x):
          ????pass
          ?
          ?
          def?colorLooker(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è)置默認(rèn)最大值
          ????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)
          ????????if?cv2.waitKey(10)?&?0xFF?==?ord('q'):
          ????????????break
          ????cv2.destroyAllWindows()
          ?
          ?
          ?
          ?
          if?__name__?==?'__main__':
          ????colorLooker(pic='1.png')
          ?
          ?
          啟動后截圖如下所示:

          借助界面中的拖動條可以很方便地進(jìn)行調(diào)節(jié),看到實時處理后的結(jié)果圖片:

          經(jīng)過調(diào)節(jié)后最終的結(jié)果如下所示:

          調(diào)整拖動條的同時,終端窗口輸出如下所示:

          到這里,我們已經(jīng)獲取到了所需要的各個維度的閾值數(shù)據(jù)了,就可以進(jìn)行后面的處理了。
          接下來我們基于上述閾值來進(jìn)行區(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)目標(biāo)對象的區(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壓縮水平方向、垂直方向、對角線方向的元素,只保留該方向的終點坐標(biāo),例如一個矩形輪廓只需要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
          for?i?in?range(len(contours)):
          ????one=contours[i]
          ????one_lk=one.tolist()
          ????if?len(one_lk)>=2:
          ????????area=cv2.contourArea(one)
          ????????length=cv2.arcLength(one,?True)
          ????????areas+=area
          ????????lengths+=length
          ????????left_list,right_list=[O[0][0]?for?O?in?one_lk],[O[0][1]?for?O?in?one_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=lambda?e: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è)計的問題,沒有考慮到過濾掉嵌套或者是包含的情況,所以這里就來處理一下:
          if?sorted_list:
          ????filter_list=filterBox(sorted_list[:5])
          ????for?one_box?in?filter_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ù)進(jìn)行可視化,借助于matplotlib繪制在同一張圖上,結(jié)果如下所示:

          左上角為原始圖片,右下角為最終處理得到的圖片,可以看到整個處理過程的變化。
          到這里本文的內(nèi)容就結(jié)束了,學(xué)習(xí)依舊在路上,歡迎交流,互相學(xué)習(xí)!

          作者:沂水寒城,CSDN博客專家,個人研究方向:機器學(xué)習(xí)、深度學(xué)習(xí)、NLP、CV

          Blog:?http://yishuihancheng.blog.csdn.net


          贊 賞 作 者



          Python中文社區(qū)作為一個去中心化的全球技術(shù)社區(qū),以成為全球20萬Python中文開發(fā)者的精神部落為愿景,目前覆蓋各大主流媒體和協(xié)作平臺,與阿里、騰訊、百度、微軟、亞馬遜、開源中國、CSDN等業(yè)界知名公司和技術(shù)社區(qū)建立了廣泛的聯(lián)系,擁有來自十多個國家和地區(qū)數(shù)萬名登記會員,會員來自以工信部、清華大學(xué)、北京大學(xué)、北京郵電大學(xué)、中國人民銀行、中科院、中金、華為、BAT、谷歌、微軟等為代表的政府機關(guān)、科研單位、金融機構(gòu)以及海內(nèi)外知名公司,全平臺近20萬開發(fā)者關(guān)注。

          長按掃碼添加“Python小助手”?

          ▼點擊成為社區(qū)會員? ?喜歡就點個在看吧

          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  精品一区二区三区四 | 91丨豆花丨成人 熟女 | 亚洲电影av | 国产日韩一区二区 | www.99热 |