2012-07-24 131 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