2012-07-24 97 views
2

Python腳本從套接字中讀取png圖像,然後試圖用OpenCV顯示,就像慢速視頻一樣。 有2個類server.py和Worker.py。 Server.py從套接字接收一個原始png並將其放在隊列中。在其自己的線程中,工作人員將png出列並顯示出來。只有第一張圖像正確顯示。其他圖像不可見(即第一個圖像保留),但ShowImage和WaitKey被調用。Python OpenCV線程

線程模型是否正確?看起來服務器套接字線程阻止OpenCV線程顯示。有沒有辦法把服務器套接字放在後臺線程上?從後臺線程調用ShowWIndow和WaitKey是否正確?我對Mac上的Python或OpenCV線程知之甚少。任何意見和建議將不勝感激。

server.py:

#! /usr/bin/env python 
import sys 
import SocketServer 
import socket 
import subprocess 
import time 
import cv 
import Worker 
import ShowImage 

HOST = 'andrew-rosenblums-macbook-pro.local' 
PORT = 3001 
FRAME_SIZE = 144*192 
data = '' 
worker = Worker.Worker() 

class SingleTCPHandler(SocketServer.BaseRequestHandler): 
    imagesSaved = 0 

    "One instance per connection. Override handle(self) to customize action." 
    def handle(self): 
     # self.request is the client connection 
     print "connection received.." 
     while True: 
      #print "calling rcv" 
      messageLength = self.request.recv(6) # Read 6 ascii char image size 
      cv.WaitKey(30) 
      if (len(messageLength) > 0): 
       print "messageLength=" + messageLength 
       iLength = int(messageLength) 
       message = '' 
       while (iLength > 0): 
        if (iLength > 1024): 
         chunk = self.request.recv(1024) 
        else: 
         chunk = self.request.recv(iLength) 
        iLength -= len(chunk) 
        message += chunk 
       print "rcvd imsg of len=" + str(len(message)) 
       worker.write(message) 

       if (SingleTCPHandler.imagesSaved == 0): 
        SingleTCPHandler.imagesSaved += 1 

     print "closing stream" 
     self.request.close() 
     print "done receiving" 

    def finish(self): 
     print "finish called" 

class SimpleServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): 
    # Ctrl-C will cleanly kill all spawned threads 
    daemon_threads = True 
    # much faster rebinding 
    allow_reuse_address = True 

    def __init__(self, server_address, RequestHandlerClass): 
     SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass) 

if __name__ == "__main__": 
    server = SimpleServer((HOST, PORT), SingleTCPHandler) 
    # terminate with Ctrl-C 
    try: 
     print "waiting for connections..." 
     server.serve_forever() 
    except KeyboardInterrupt: 
     sys.exit(0) 

Worker.py

#! /usr/bin/env python 
import time 
from threading import Thread 
from Queue import Queue 
import sys 
import cv 
import cv2 
import numpy as np 
import Image 
from cStringIO import StringIO 

class Worker(Thread): 

    count = 0 

    def __init__(self): 
     Thread.__init__(self) 

     self.cvImage = None 
     cv.NamedWindow('display') 
     cv.MoveWindow('display', 10, 10) 

     self.queue = Queue() 
     self.writer = None 
     # Daemon threads won't prevent process from exiting 
     self.setDaemon(True) 

     # Start ourselves automatically 
     self.start() 
     print "Worker started" 

    def run(self): 
     writer = None 
     while 1: 
      frame = None 

      try: 
       #frame = self.queue.get(block=False) 
       frame = self.queue.get() 
       print "display izeof rawImage=" + str(len(frame)) 

       #convert to mat 
       pilImage = Image.open(StringIO(frame));#.convert("RGB"); 

       bgrImage = np.array(pilImage) 

       cvBgrImage = cv.fromarray(bgrImage) 
       self.cvImage = cv.CreateImage(cv.GetSize(cvBgrImage),8,3) 
       cv.CvtColor(cvBgrImage, self.cvImage, cv.CV_BGR2RGB) 

       #show it 
       cv.ShowImage('display', self.cvImage) 
       cv.WaitKey(30) 
       self.cvImage = None 
      except: 
       frame = None 

     print "done with thread" 

    # Requests from main thread 
    def write(self, frame): 
     self.queue.put(frame) 

    def stop(self): 
     self.queue.put(None) 

回答

3

好咄,答案很簡單:OpenCV中的ShowImage和WaitKey必須在主線程。我想這是GUI線程。 ServerSockets被推送到它自己的線程,這在Python中非常容易。所有你需要的是這樣的:

UDPThread = Thread(target = UDPServer.run) 
s.start(UPDThread) 
+1

其實,他們不必從主線程運行。我發現我可以使用'cv2.imshow'和'cv2.waitKey'(其中'delay'既爲零又非零)來自其他線程。儘管在最後(如果顯示一個圖像循環)'cv2.waitKey'後必須調用'cv2.destroyAllWindows',以防止最後一個圖像掛起。我也在線程中創建了命名窗口(隱式地通過'cv2.imshow')。 – 101 2015-07-13 01:40:28

+0

這很奇怪。我在嘗試從非主線程使用cv2.waitKey和cv2.imshow時出現錯誤「QObject :: startTimer:定時器不能從另一個線程啓動」。顯示圖像,但waitKey似乎無法測量延遲並阻止,直到按下該鍵。 – ogurets 2017-02-06 17:36:59