• <strike id="fdgpu"><input id="fdgpu"></input></strike>
    <label id="fdgpu"></label>
    <s id="fdgpu"><code id="fdgpu"></code></s>

  • <label id="fdgpu"></label>
  • <span id="fdgpu"><u id="fdgpu"></u></span>

    <s id="fdgpu"><sub id="fdgpu"></sub></s>
    您當前的位置是:  首頁(yè) > 新聞 > 文章精選 >
     首頁(yè) > 新聞 > 文章精選 >

    教你如何結合的WebRTC與TensorFlow實(shí)現圖像檢測(上篇)

    2018-01-10 13:56:18   作者:   來(lái)源:聲網(wǎng)Agora   評論:0  點(diǎn)擊:


      摘要:本文作者介紹了結合的WebRTC與TensorFlow實(shí)現圖像檢測的具體過(guò)程,不論對于TensorFlow的使用者,還是的WebRTC的開(kāi)發(fā)者來(lái)講都有參考意義由于文章較長(cháng),我們將分為上下篇進(jìn)行連載。
      TensorFlow是目前最流行的機器學(xué)習框架之一。TensorFlow的一大優(yōu)勢是,它的很多庫都有人積極進(jìn)行維護和更新。而我最喜歡的其中一個(gè)庫就是TensorFlow 對象檢測API .Tensorflow對象檢測API可以對一張圖形上的多個(gè)對象進(jìn)行分類(lèi),并提供它們的具體位置。該API在將近1000個(gè)對象類(lèi)上進(jìn)行了預先訓練,可提供各種經(jīng)過(guò)預先訓練的模型,讓你可以在速度與準確性之間權衡取舍。
      有這些模型的指引固然很好,但所有這些模型都要使用圖像才能發(fā)揮作用,而這些圖像則需要你自行添加到一個(gè)文件夾中。我其實(shí)很想將其與實(shí)時(shí)的的WebRTC流配合到一起,通過(guò)網(wǎng)絡(luò )實(shí)現實(shí)時(shí)的計算機視覺(jué)。由于未能找到這方面的任何例子或指南,我決定寫(xiě)這篇博文來(lái)介紹具體的實(shí)現方法。對于使用RTC的人,可以將本文作為一篇快速指南加以參考,了解如何使用TensorFlow來(lái)處理的WebRTC流。對于使用TensorFlow的人士,則可以將本文作為一份快速簡(jiǎn)介,了解如何向自己的項目中添加的WebRTC。使用的WebRTC的人需要對Python的比較熟悉。而使用TensorFlow的人則需要熟悉網(wǎng)絡(luò )交互和一些JavaScript的。
      本文不適合作為WebRTC或TensorFlow的入門(mén)指南使用。如需這樣的指南,應參考TensorFlow 入門(mén)指南,WebRTC 入門(mén)指南等,網(wǎng)上的相關(guān)介紹與指南數不勝數。
      利用Tensor Flow和WebRTC檢測貓咪
      直接告訴我如何實(shí)現吧
      如果你來(lái)這里只是為了快速找到一些參考信息,或者懶得讀詳細的文字介紹,按照下面的方法即可快速著(zhù)手。首先安裝Docker 。加載一個(gè)命令提示窗口,接著(zhù)鍵入下面的命令:
      然后在瀏覽器地址欄中鍵入并轉到http:// localhost:5000 / local ,接受攝像頭權限請求,你應該會(huì )看到類(lèi)似下面的界面:
      基本架構
      我們首先建立一個(gè)基本架構,用于在本地將一個(gè)本地網(wǎng)絡(luò )攝像頭流從WebRTC的getUserMedia 發(fā)送到一個(gè)Python服務(wù)器,這要用到Flask 網(wǎng)絡(luò )服務(wù)器和TensorFlow對象檢測API(Object Detection API)。具體的設置大致如下圖所示。
      為搭配使用的WebRTC與TensorFlow對象檢測API而建立的基本架構
      Flask將提供html和JavaScript文件供瀏覽器呈現。getUserMedia.js負責抓取本地視頻流。接下來(lái),objDetect.js將使用HTTP POST 方法向TensorFlow對象檢測API發(fā)送圖像,該API則返回它所有看到的對象(它稱(chēng)之為“類(lèi)”)及對象在圖像中的位置。我們會(huì )將這些詳細信息封裝到一個(gè)JSON對象中,然后將該對象發(fā)回給objDetect.js,這樣我們就能將我們所看到的對象的方框和標簽顯示出來(lái)。
      配置
      設置和前提條件
      在開(kāi)始之前,我們需要先對Tensorflow和對象檢測API進(jìn)行一些設置。
      使用泊塢輕松完成設置
      我在OSX,Windows 10和Raspbian已經(jīng)設置過(guò)好幾次(過(guò)程可不簡(jiǎn)單)。各種版本依賴(lài)關(guān)系錯綜復雜,把這些關(guān)系理順并非易事,特別是當你只是想看看一些前期工作是否行得通時(shí),你可能會(huì )感到氣餒。我推薦使用泊塢來(lái)避免這些棘手問(wèn)題。你將需要學(xué)習泊塢,這也是非學(xué)不可的東西,與其試著(zhù)構建合適的的Protobuf 版本,倒不如花些時(shí)間學(xué)習它來(lái)得更為高效。TensorFlow項目維護了一些官方的Docker映像,比如tensorflow / tensorflow 。
      如果你使用泊塢窗,我們就可以使用我為這篇博文創(chuàng )建的映像在命令行中,請運行以下命令:
      請注意,在Windows 10命令行中,請使用%cd%。
      。看到這里,你應該已經(jīng)進(jìn)入了碼頭工人容器現在,請運行:
      這樣,就會(huì )使用最新的TensorFlow Docker映像,并將Docker主機上的端口5000連接到端口5000,將容器命名為tf-webrtchacks,將一個(gè)本地目錄映射到容器中的一個(gè)新/ code目錄,將該目錄設為默認目錄(我們接下來(lái)將在該目錄中操作),然后運行的bash以便進(jìn)行命令行交互。完成這些準備工作后,我們才能開(kāi)始。
      如果你才剛開(kāi)始接觸TensorFlow,可能需要先按照噸ensorflow / tensorflow 中的說(shuō)明運行初始Jupyter筆記本,然后再回來(lái)執行上述命令。
      另一種麻煩的實(shí)現方法
      如果你打算從頭開(kāi)始,則需要安裝TensorFlow,它自己有很多依賴(lài)項,比如Python.TensorFlow項目針對各種平臺都提供了指南,具體請訪(fǎng)問(wèn)https://www.tensorflow.org/install 。對象檢測API有也。自己的安裝說(shuō)明,以及一些額外的依賴(lài)項完成這些準備工作后,請運行下面的命令:
      這樣,就應該安裝好了所有的Python的依賴(lài)項,將相應的Tensorflow對象檢測API文件都復制了過(guò)來(lái),并安裝了Protobufs。如果這一步行不通,我建議檢查setup.py,然后手動(dòng)在其中運行命令,以解決存在的任何問(wèn)題。
      第1部分 - 確保Tensorflow正常工作
      為確保TensorFlow對象檢測API正常工作,我們首先從用于演示對象檢測的官方版本JupyterNotebook經(jīng)調整后的版本著(zhù)手。我將此文件保存為object_detection_tutorial.py 。
      如果你剪切并粘貼該筆記本的每個(gè)部分,得到的結果應如下所示:(由于此段代碼較長(cháng),截圖會(huì )影響閱讀,我們更換為文字排版,左右拖動(dòng)可查看長(cháng)代碼)
      # IMPORTS
      import numpy as np
      import os
      import six.moves.urllib as urllib
      import sys
      import tarfile
      import tensorflow as tf
      import zipfile
      from collections import defaultdict
      from io import StringIO
      # from matplotlib import pyplot as plt ### CWH
      from PIL import Image
      if tf.__version__ != '1.4.0':
      raise ImportError('Please upgrade your tensorflow installation to v1.4.0!')
      # ENV SETUP  ### CWH: remove matplot display and manually add paths to references
      '''
      # This is needed to display the images.
      %matplotlib inline
      # This is needed since the notebook is stored in the object_detection folder.
      sys.path.append("")
      '''
      # Object detection imports
      from object_detection.utils import label_map_util    ### CWH: Add object_detection path
      #from object_detection.utils import visualization_utils as vis_util ### CWH: used for visualization
      # Model Preparation
      # What model to download.
      MODEL_NAME = 'ssd_mobilenet_v1_coco_2017_11_17'
      MODEL_FILE = MODEL_NAME + '.tar.gz'
      DOWNLOAD_BASE = 'http://download.tensorflow.org/models/object_detection/'
      # Path to frozen detection graph. This is the actual model that is used for the object detection.
      PATH_TO_CKPT = MODEL_NAME + '/frozen_inference_graph.pb'
      # List of the strings that is used to add correct label for each box.
      PATH_TO_LABELS = os.path.join('object_detection/data', 'mscoco_label_map.pbtxt') ### CWH: Add object_detection path
      NUM_CLASSES = 90
      # Download Model
      opener = urllib.request.URLopener()
      opener.retrieve(DOWNLOAD_BASE + MODEL_FILE, MODEL_FILE)
      tar_file = tarfile.open(MODEL_FILE)
      for file in tar_file.getmembers():
      file_name = os.path.basename(file.name)
      if 'frozen_inference_graph.pb' in file_name:
      tar_file.extract(file, os.getcwd())
      # Load a (frozen) Tensorflow model into memory.
      detection_graph = tf.Graph()
      with detection_graph.as_default():
      od_graph_def = tf.GraphDef()
      with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:
      serialized_graph = fid.read()
      od_graph_def.ParseFromString(serialized_graph)
      tf.import_graph_def(od_graph_def, name='')
      # Loading label map
      label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
      categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
      category_index = label_map_util.create_category_index(categories)
      # Helper code
      def load_image_into_numpy_array(image):
      (im_width, im_height) = image.size
      return np.array(image.getdata()).reshape(
      (im_height, im_width, 3)).astype(np.uint8)
      # Detection
      # For the sake of simplicity we will use only 2 images:
      # image1.jpg
      # image2.jpg
      # If you want to test the code with your images, just add path to the images to the TEST_IMAGE_PATHS.
      PATH_TO_TEST_IMAGES_DIR = 'object_detection/test_images' #cwh
      TEST_IMAGE_PATHS = [ os.path.join(PATH_TO_TEST_IMAGES_DIR, 'image{}.jpg'.format(i)) for i in range(1, 3) ]
      # Size, in inches, of the output images.
      IMAGE_SIZE = (12, 8)
      with detection_graph.as_default():
      with tf.Session(graph=detection_graph) as sess:
      # Definite input and output Tensors for detection_graph
      image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
      # Each box represents a part of the image where a particular object was detected.
      detection_boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
      # Each score represent how level of confidence for each of the objects.
      # Score is shown on the result image, together with the class label.
      detection_scores = detection_graph.get_tensor_by_name('detection_scores:0')
      detection_classes = detection_graph.get_tensor_by_name('detection_classes:0')
      num_detections = detection_graph.get_tensor_by_name('num_detections:0')
      for image_path in TEST_IMAGE_PATHS:
      image = Image.open(image_path)
      # the array based representation of the image will be used later in order to prepare the
      # result image with boxes and labels on it.
      image_np = load_image_into_numpy_array(image)
      # Expand dimensions since the model expects images to have shape: [1, None, None, 3]
      image_np_expanded = np.expand_dims(image_np, axis=0)
      # Actual detection.
      (boxes, scores, classes, num) = sess.run(
      [detection_boxes, detection_scores, detection_classes, num_detections],
      feed_dict={image_tensor: image_np_expanded})
      ### CWH: below is used for visualizing with Matplot
      '''
      # Visualization of the results of a detection.
      vis_util.visualize_boxes_and_labels_on_image_array(
      image_np,
      np.squeeze(boxes),
      np.squeeze(classes).astype(np.int32),
      np.squeeze(scores),
      category_index,
      use_normalized_coordinates=True,
      line_thickness=8)
      plt.figure(figsize=IMAGE_SIZE)
      plt.imshow(image_np)
      '''
      在這里我就不再贅述實(shí)際TensorFlow代碼的作用了,這方面的信息可在Jupyter _ECSHOP演示及其他教程中找到。我將重點(diǎn)介紹我們對代碼所做的修改。
      我注釋了幾個(gè)小節:
      更改了一些位置引用
      刪除了對Python matplot的所有引用。Python matplot用于在GUI環(huán)境中以可視化方式呈現輸出結果。在我的Docker環(huán)境中沒(méi)有設置它 - 根據你采用的具體運行方式,可以酌情決定是否保留這些引用。
      對象檢測API的輸出結果
      正如第111行所示,對象檢測API輸出4種對象:
    • 類(lèi) - 一個(gè)由對象名組成的數組
    • 分值 - 一個(gè)由置信度分值組成的數組
    • 方框 - 檢測到的每個(gè)對象所在的位置
    • 數量 - 檢測到的對象總數
      類(lèi),分值和方框都是相互并列,大小相等的數組,因此類(lèi)[N]與分數[N]和盒[n]的都是一一對應的。
      由于我刪去了可視化功能,我們需要通過(guò)某種方式來(lái)查看結果,所以我們要把下面的命令添加到文件末尾:
      第一個(gè)np.squeeze部分只是將多維數組輸出縮減成一維,這與原來(lái)的可視化代碼一樣。我認為這是TensorFlow的一個(gè)副產(chǎn)品,因為它通常會(huì )輸出多維數組。
      接著(zhù)我們要為它輸出的分值設置一個(gè)閾值。好像TensorFlow默認會(huì )返回100個(gè)對象。其中很多對象嵌套在置信度更高的對象內或與這些對象重疊。在選擇閾值方面我還沒(méi)有發(fā)現任何最佳做法,不過(guò)對于這些示例圖像來(lái)說(shuō),50%似乎是合適的。
      最后,我們需要循環(huán)遍歷這些數組,直接輸出那些超過(guò)閾值的分值。
      如果運行下面的命令:
      應該會(huì )獲得下面的輸出:
      第2部分 - 打造一項對象API網(wǎng)絡(luò )服務(wù)
      在這一部分,我們將對教程代碼作一些改動(dòng),以將其作為一項網(wǎng)絡(luò )服務(wù)加以運行。我在Python方面的經(jīng)驗頗為有限(主要在Raspberry Pi項目中使用過(guò)),所以如有不對的地方,添加請備注或提交拉取請求,以便我可以修正。
      2.1將演示代碼轉變成一項服務(wù)
      至此我們已經(jīng)讓TensorFlow Object API能夠正常工作了,接下來(lái)我們就將它封裝成一個(gè)可以調用的函數。我將演示代碼復制到了一個(gè)名為object_detection_api.py 的新python文件中。你可以看到,我刪除了很多沒(méi)有用到或注釋掉的行,以及用于將詳細信息輸出到控制臺的部分(暫時(shí)刪除)。
      由于我們要將這些信息輸出到網(wǎng)絡(luò )上,因此最好將我們的輸出結果封裝成一個(gè)JSON對象為此,請務(wù)必向你導入的內容中添加一個(gè)importjso語(yǔ)句,然后再添加下面的命令:
      接下來(lái),我們要重復利用之前的代碼創(chuàng )建一個(gè)get_objects函數:
      在此函數中我們添加了一個(gè)圖像輸入參數和一個(gè)默認為0.5的閾值。其余內容都是在演示代碼的基礎上重構的。
      現在我們再向此函數添加一些代碼,以查詢(xún)具體的值并將它們輸出到一個(gè)JSON對象中:
      這一次我們是使用對象類(lèi)來(lái)創(chuàng )建一些初始元數據并將這些元數據添加到輸出列表中。然后我們使用循環(huán)向此列表中添加對象數據。最后,將此列表轉換成JSON并予以返回。
      之后,我們來(lái)創(chuàng )建一個(gè)測試文件(這里要提醒自己:先做測試),以檢查它是否調用了object_detection_test.py :
      至此萬(wàn)事俱備,接下來(lái)就是運行了。
      除了前面的控制臺輸出之外,你應該還會(huì )看到一個(gè)JSON字符串:
      2.2添加一個(gè)網(wǎng)絡(luò )服務(wù)器
      我們已經(jīng)有了函數 - 接下來(lái)我們就用它來(lái)打造一項網(wǎng)絡(luò )服務(wù)。
      先使用測試用的路由(路由)運行
      我們有了一個(gè)可以輕松添加到網(wǎng)絡(luò )服務(wù)的良好API。我發(fā)現使用Flask 是最簡(jiǎn)單的測試方法。我們來(lái)創(chuàng )建一個(gè)server.py ,然后執行一次快速測試:
      現在,運行該服務(wù)器:
      確保該服務(wù)正常工作
      然后調用該網(wǎng)絡(luò )服務(wù)就我自己的情況而言,我只是從主機運行了下面的命令(因為我的泊塢實(shí)例現在正在前臺運行該服務(wù)器)。:
      。json.tool將幫助你為輸出結果設置格式你應該會(huì )看到下面的結果:
      好了,接下來(lái)我們就要接受一個(gè)包含一個(gè)圖片文件及其他一些參數的POST,使用真實(shí)路由運行了為此,需要在/測試路由函數下添加一個(gè)新的和/或圖像路由:
      這樣就會(huì )從一個(gè)采用表單編碼方式的POST中獲取圖片,并且可以選擇指定一個(gè)閾值,然后將該圖片傳遞給我們的object_detection_api。
      我們來(lái)測試一下:
      這時(shí)看到的結果應該與上面使用/測試路徑時(shí)相同。繼續測試,可以指定你任選的其他本地圖像的路徑。
      讓該服務(wù)在本地主機以外的位置也能正常工作
      如果你打算在本地主機上運行瀏覽器,可能就不需要再做些什么。但如果是真實(shí)的服務(wù),甚至是在需要運行很多測試的情況下,這就不太現實(shí)了。如果要跨網(wǎng)絡(luò )運行網(wǎng)絡(luò )服務(wù),或者使用其他資源運行網(wǎng)絡(luò )服務(wù),都需要用到CORS幸好,在路由前添加以下代碼就可以輕松解決這一問(wèn)題:
      讓該服務(wù)支持安全源
      最佳做法是搭配HTTPS使用的WebRTC,因為鉻和Safari瀏覽器等瀏覽器若不作專(zhuān)門(mén)配置,則僅支持安全源(不過(guò)鉻可以很好地支持本地主機,你也可以將野生設為允許在非安全網(wǎng)站上捕獲信息-到跳轉此處。的調試工具部分了解詳情)為此,你需要獲取一些SSL證書(shū)或生成一些自托管證書(shū)我將我自己的證書(shū)放在了SSL /目錄中,然后將最后一行app.run更改為:
      如果你使用的是自簽名證書(shū),你在使用卷曲進(jìn)行測試時(shí)可能需要添加--insecure選項:
    • 嚴格來(lái)講并非一定要生成你自己的證書(shū),而且這會(huì )增加一定的工作量,所以在server.py最底部,我依然讓SSL版本保持被注釋掉的狀態(tài)。
    • 如果是要投入生產(chǎn)環(huán)境中使用的應用程序,你可能需要使用的nginx之類(lèi)的代理向外發(fā)送HTTPS,同時(shí)在內部依然使用HTTP(此外還要做很多其他方面的改進(jìn))。
    • 添加一些路由以便提供我們的網(wǎng)頁(yè)
    • 在開(kāi)始介紹瀏覽器端的工作之前,我們先為后面需要用到的一些路由生成存根為此,請將下面的代碼放在索引()路由后面:
    • 蟒蛇方面的工作到此就結束了。接下來(lái)我們將用到的JavaScript,并且需要編寫(xiě)一些HTML。
    • 我們將在下篇分享瀏覽器端的開(kāi)發(fā),以及優(yōu)化方面經(jīng)驗。
    【免責聲明】本文僅代表作者本人觀(guān)點(diǎn),與CTI論壇無(wú)關(guān)。CTI論壇對文中陳述、觀(guān)點(diǎn)判斷保持中立,不對所包含內容的準確性、可靠性或完整性提供任何明示或暗示的保證。請讀者僅作參考,并請自行承擔全部責任。

    專(zhuān)題

    亚洲精品网站在线观看不卡无广告,国产a不卡片精品免费观看,欧美亚洲一区二区三区在线,国产一区二区三区日韩 连城县| 阿拉善左旗| 都兰县| 陆丰市| 陆丰市| 清新县| 五大连池市| 唐山市| 璧山县| 新竹市| 大英县| 绥滨县| 东兰县| 绥阳县| 阿勒泰市| 清新县| 东阿县| 延安市| 延长县| 曲靖市| 奉节县| 泰顺县| 南安市| 阳高县| 崇信县| 康定县| 滨州市| 囊谦县| 全南县| 尖扎县| 东明县| 镇安县| 休宁县| 西乡县| 峨边| 江都市| 革吉县| 成安县| 吉安县| 诸暨市| 延寿县| http://444 http://444 http://444 http://444 http://444 http://444