2017-02-16 38 views
2

私は/ランドマークワット顔認識を実行するためのOpenCVとDLIBを使用しています、ウェブカメラストリームから住んでいます。言語はPythonです。私のMacBookラップトップでは正常に動作しますが、デスクトップコンピュータから24時間365日稼働する必要があります。このコンピュータは、Debian Jessieが動作するPCインテル®Core™2 Quad CPU Q6600 @ 2.40GHz 32ビット版です。 パフォーマンスの低下は劇的です:処理のために10秒の遅延があります!OpenCVの/ Pythonの:ライブ顔認識のためのマルチスレッド

Iは、従って性能を得るためにマルチスレッドに見:

  1. Iは最初のOpenCVによるサンプルコードを試みたが、結果は素晴らしいです! 4つのコアすべてが100%ヒットし、パフォーマンスははるかに優れています。
  2. フレーム処理コードを自分のコードに置き換えても、パフォーマンスは向上しません。 1つのコアだけが100%をヒットし、他のコアは非常に低く保たれます。 私はそれがマルチスレッドではさらに悪いと思っています。

私はdlibサンプルコードから顔のランドマークコードを得ました。私はそれがおそらく最適化できることを知っていますが、私は理解したいなぜ私は(古い)コンピュータのフルパワーをマルチスレッドで使用できないのですか?

私は以下の私のコードをドロップします

、おかげで読書のためにたくさん:)

from __future__ import print_function 
 

 
import numpy as np 
 
import cv2 
 
import dlib 
 

 
from multiprocessing.pool import ThreadPool 
 
from collections import deque 
 

 
from common import clock, draw_str, StatValue 
 
import video 
 

 
class DummyTask: 
 
    def __init__(self, data): 
 
     self.data = data 
 
    def ready(self): 
 
     return True 
 
    def get(self): 
 
     return self.data 
 

 
if __name__ == '__main__': 
 
    import sys 
 

 
    print(__doc__) 
 

 
    try: 
 
     fn = sys.argv[1] 
 
    except: 
 
     fn = 0 
 
    cap = video.create_capture(fn) 
 
    
 
    #Face detector 
 
    detector = dlib.get_frontal_face_detector() 
 

 
    #Landmarks shape predictor 
 
    predictor = dlib.shape_predictor("landmarks/shape_predictor_68_face_landmarks.dat") 
 

 
    # This is where the facial detection takes place 
 
    def process_frame(frame, t0, detector, predictor): 
 
     # some intensive computation... 
 
     gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 
 
     clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) 
 
     clahe_image = clahe.apply(gray) 
 
     detections = detector(clahe_image, 1) 
 
     for k,d in enumerate(detections): 
 
      shape = predictor(clahe_image, d) 
 
      for i in range(1,68): #There are 68 landmark points on each face 
 
       cv2.circle(frame, (shape.part(i).x, shape.part(i).y), 1, (0,0,255), thickness=2) 
 
     return frame, t0 
 

 
    threadn = cv2.getNumberOfCPUs() 
 
    pool = ThreadPool(processes = threadn) 
 
    pending = deque() 
 

 
    threaded_mode = True 
 

 
    latency = StatValue() 
 
    frame_interval = StatValue() 
 
    last_frame_time = clock() 
 
    while True: 
 
     while len(pending) > 0 and pending[0].ready(): 
 
      res, t0 = pending.popleft().get() 
 
      latency.update(clock() - t0) 
 
      draw_str(res, (20, 20), "threaded  : " + str(threaded_mode)) 
 
      draw_str(res, (20, 40), "latency  : %.1f ms" % (latency.value*1000)) 
 
      draw_str(res, (20, 60), "frame interval : %.1f ms" % (frame_interval.value*1000)) 
 
      cv2.imshow('threaded video', res) 
 
     if len(pending) < threadn: 
 
      ret, frame = cap.read() 
 
      t = clock() 
 
      frame_interval.update(t - last_frame_time) 
 
      last_frame_time = t 
 
      if threaded_mode: 
 
       task = pool.apply_async(process_frame, (frame.copy(), t, detector, predictor)) 
 
      else: 
 
       task = DummyTask(process_frame(frame, t, detector, predictor)) 
 
      pending.append(task) 
 
     ch = cv2.waitKey(1) 
 
     if ch == ord(' '): 
 
      threaded_mode = not threaded_mode 
 
     if ch == 27: 
 
      break 
 
cv2.destroyAllWindows()

答えて

0

のThreadPoolを使用して多くの経験を持っていますが、示すように私はいつもちょうどプロセスを使用しないでください以下。あなたは、あなたのニーズに合わせてこのコードを簡単に編集できるはずです。私はあなたの実装を念頭に置いてこれを書いた。

このコードはコア数を取得しますが、多くのワーカープロセスはすべて目的の機能を並列に実装します。それらはすべて入力のためのフレームのキューを共有し、すべてが同じ出力待ち行列に置かれ、メインが取得して表示するキューです。各キューには最大サイズ(この場合は5)が設定されています。これにより、処理に要するCPU時間にもかかわらず、常に比較的ライブタイムになります。

import numpy as np 
 
import cv2 
 

 
from multiprocessing import Process, Queue 
 
import time 
 

 
#from common import clock, draw_str, StatValue 
 
#import video 
 

 
class Canny_Process(Process): 
 
    
 
    def __init__(self,frame_queue,output_queue): 
 
     Process.__init__(self) 
 
     self.frame_queue = frame_queue 
 
     self.output_queue = output_queue 
 
     self.stop = False 
 
     #Initialize your face detectors here 
 
     
 

 
    def get_frame(self): 
 
     if not self.frame_queue.empty(): 
 
      return True, self.frame_queue.get() 
 
     else: 
 
      return False, None 
 

 
    def stopProcess(self): 
 
     self.stop = True 
 
      
 
    def canny_frame(self,frame): 
 
     # some intensive computation... 
 
     gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 
 
     edges = cv2.Canny(gray, 50, 100) 
 
     
 
     #To simulate CPU Time 
 
     ############################# 
 
     for i in range(1000000): 
 
      x = 546*546 
 
      res = x/(i+1) 
 
     ############################# 
 
     'REPLACE WITH FACE DETECT CODE HERE' 
 

 
     if self.output_queue.full(): 
 
      self.output_queue.get_nowait() 
 
     self.output_queue.put(edges) 
 

 
    def run(self): 
 
     while not self.stop: 
 
      ret, frame = self.get_frame() 
 
      if ret: 
 
       self.canny_frame(frame) 
 

 

 
if __name__ == '__main__': 
 

 
    frame_sum = 0 
 
    init_time = time.time() 
 

 
    def put_frame(frame): 
 
     if Input_Queue.full(): 
 
      Input_Queue.get_nowait() 
 
     Input_Queue.put(frame) 
 

 
    def cap_read(cv2_cap): 
 
     ret, frame = cv2_cap.read() 
 
     if ret: 
 
      put_frame(frame) 
 
     
 
    cap = cv2.VideoCapture(0) 
 

 
    threadn = cv2.getNumberOfCPUs() 
 

 
    threaded_mode = True 
 

 
    process_list = [] 
 
    Input_Queue = Queue(maxsize = 5) 
 
    Output_Queue = Queue(maxsize = 5) 
 

 
    for x in range((threadn -1)):  
 
     canny_process = Canny_Process(frame_queue = Input_Queue,output_queue = Output_Queue) 
 
     canny_process.daemon = True 
 
     canny_process.start() 
 
     process_list.append(canny_process) 
 

 
    ch = cv2.waitKey(1) 
 
    cv2.namedWindow('Threaded Video', cv2.WINDOW_NORMAL) 
 
    while True:   
 
     cap_read(cap) 
 
     
 
     if not Output_Queue.empty(): 
 
      result = Output_Queue.get() 
 
      cv2.imshow('Threaded Video', result) 
 
      ch = cv2.waitKey(5) 
 

 
     if ch == ord(' '): 
 
      threaded_mode = not threaded_mode 
 
     if ch == 27: 
 
      break 
 
    cv2.destroyAllWindows()

これはちょうどあなたの顔の検出を行うために、私の気の利いた機能を変更するトリックを行う必要があります。私はあなたのコードからこれを書いて、2つを比較しました。これははるかに高速です。私はマルチプロセッシングを使用しています。ここでのプロセスです。 Pythonのプロセスでは、本当に並列であり、スレッドはGILのためではありません。私は2つのキューを使用して、メインとプロセスの間でデータをやり取りしています。キューはスレッドとプロセスの両方で安全です。

+0

すべてのコードを書く時間をとってくれてありがとう:)それは何らかの理由でうまくいきません。私は今週それをダイビングしようとしています。私はちょうどi7-2600K @ @ 3.40Ghzのためにコンピュータを変えました、そして、私はまだパフォーマンスの問題を抱えています!ボトルネックはどこか他の場所だと思います。 **おそらくOSXとDebianのアーキテクチャのどこかにあるのでしょうか?**すべてがOSXでうまく動作するからです!もう一度おねがいします。今週の結果についてお知らせします:) – Simon

+0

コードやパフォーマンスはどういうものですか?コードは実行されていますが、まだ十分に速くないか、コードがまったく実行されていませんか?あなたが私にエラーを与えるなら、私はそれが何であるかを伝えるかもしれません。ありがとう –

+0

コードは実行されますが、期待どおりに実行されません。私はこのファイルにログを記録しました:https://docs.google.com/document/d/1cs9Jpf03EjTPHommMLmJ_84PxoAT3ATtmFlvBEg6l6I/edit?usp=sharingもう一度、まだ深く掘り下げる時間はありませんでした。明日までに再度、感謝します :) – Simon

2

パフォーマンスの問題は、dlibのコンパイルが不適切なためです。 pip install dlibは、適切なコンパイルと比べて何らかの理由で非常にゆっくり実行されます。私はこのように約10秒の遅れから約2秒に行きました。だから、私はマルチスレッド/処理を必要としませんでしたが、私はスピードをさらに高めるためにそれに取り組んでいます。助けてくれてありがとう:

0

私はPのような簡略化されたアプローチを試みました。Roは、出力キューに書き込むプロセスで彼の答えに言及しましたが、何らかの理由でキューはすべてのプロセスが同時にそれを書き込んだので、ほとんどの時間ロックされていました。 (ちょうど私の推測)私はおそらく何か間違っていました。

私はパイプを使用して終了しました。

コードは厄介です。もし私が数時間前に私だったら。私はまだ実際には努力なしで実行される例を見つけることがうれしいです。

from multiprocessing import Process, Queue, Manager,Pipe 
import multiprocessing 
import face_recognition as fik 
import cv2 
import time 


video_input = 0 

obama_image = fik.load_image_file("obama.png") 
obama_face_encoding = fik.face_encodings(obama_image)[0] 



quality = 0.7 


def f(id,fi,fl): 
    import face_recognition as fok 

    while True: 
     small_frame = fi.get() 
     print("running thread"+str(id)) 
     face_locations = fok.face_locations(small_frame) 

     if(len(face_locations)>0): 
      print(face_locations) 
      for (top7, right7, bottom7, left7) in face_locations: 

       small_frame_c = small_frame[top7:bottom7, left7:right7] 
       fl.send(small_frame_c) 

fps_var =0 
if __name__ == '__main__': 
     multiprocessing.set_start_method('spawn') 


     # global megaman 
     with Manager() as manager: 

      video_capture = cv2.VideoCapture(video_input) 

      fi = Queue(maxsize=14) 

      threads = 8 
      proc = [] 

      parent_p = [] 
      thread_p = [] 
      # procids = range(0,threads) 
      for t in range(0,threads): 
       p_t,c_t = Pipe() 
       parent_p.append(p_t) 
       thread_p.append(c_t) 
       print(t) 
       proc.append(Process(target=f, args=(t,fi,thread_p[t]))) 
       proc[t].start() 


      useframe = False 

      frame_id = 0 
      while True: 
       # Grab a single frame of video 
       ret, frame = video_capture.read() 
       effheight, effwidth = frame.shape[:2] 
       if effwidth < 20: 
        break 
       # Resize frame of video to 1/4 size for faster face recognition processing 
       xxx = 930 
       yyy = 10/16 #0.4234375 
       small_frame = cv2.resize(frame, (xxx, int(xxx*yyy))) 
       if frame_id%2 == 0: 
        if not fi.full(): 


         fi.put(small_frame) 

         print(frame_id) 

         cv2.imshow('Video', small_frame) 


         print("FPS: ", int(1.0/(time.time() - fps_var))) 
         fps_var = time.time() 


       #GET ALL DETECTIONS 
       for t in range(0,threads): 
        if parent_p[t].poll(): 
         small_frame_c = parent_p[t].recv() 
         cv2.imshow('recc', small_frame_c) 
         height34, width34 = small_frame_c.shape[:2] 
         # print fsizeee 
         if(width34<20): 
          print("face 2 small") 
          print(width34) 
          break 
         face_encodings_cam = fik.face_encodings(small_frame_c,[(0, width34, height34, 0)]) 

         match = fik.compare_faces([obama_face_encoding], face_encodings_cam[0]) 
         name = "Unknown" 

         if match[0]: 
          name = "Barack" 

         print(name) 
         break 

       frame_id += 1 

       # Hit 'q' on the keyboard to quit! 
       if cv2.waitKey(1) & 0xFF == ord('q'): 
        break