1

假设我们想通过从先前收集的一组图像和标签中预测图像标签来驾驶自动驾驶汽车(机器学习应用程序)。对于这项任务,汽车通过蓝牙串行 (rfcomm) 连接到主机(带有 *NIX 的 PC),图像直接从 Android 手机使用 IP 网络摄像头进行流式传输,同时,PC 正在运行一个程序来链接这个两个功能,在创建的绘图环境中显示捕获的图像pygame,并使用串行将指令发送回汽车。

目前,我尝试使用该multiprocessing模块实现这些流程,似乎可以工作,但是当我执行客户端时,绘图函数(if __name__ == '__main__')在getKeyPress()函数结束后工作。

问题是:是否可以将包含在 中的绘图函数if __name__ == '__main__'与在 中声明的进程并行或同步getKyPress(),从而使程序在两个独立的进程中工作?

这是到目前为止实现的代码:

import urllib
import time
import os
import sys
import serial
import signal
import multiprocessing 
import numpy as np
import scipy
import scipy.io as sio
import matplotlib.image as mpimg
from pygame.locals import *


PORT = '/dev/rfcomm0'
SPEED = 115200

ser = serial.Serial(PORT)

status = False
move = None
targets = []
inputs = []
tic = False



def getKeyPress():
    import pygame
    pygame.init()
    global targets
    global status
    while not status:
          pygame.event.pump()
          keys = pygame.key.get_pressed()
          targets, status = processOutputs(targets, keys)
    targets = np.array(targets)
    targets = flattenMatrix(targets)
    sio.savemat('targets.mat', {'targets':targets})       


def rgb2gray(rgb):
    r, g, b = np.rollaxis(rgb[...,:3], axis = -1)
    return 0.299 * r + 0.587 * g + 0.114 * b

def processImages(inputX, inputs):
    inputX = flattenMatrix(inputX)
    if len(inputs) == 0:
       inputs = inputX
    elif inputs.shape[1] >= 1:
       inputs = np.hstack((inputs, inputX))
    return inputs

def flattenMatrix(mat):
    mat = mat.flatten(1)
    mat = mat.reshape((len(mat), 1))
    return mat

def send_command(val):
    connection = serial.Serial( PORT,
                                SPEED,
                                timeout=0,
                                stopbits=serial.STOPBITS_TWO
                                )
    connection.write(val)
    connection.close()

def processOutputs(targets, keys):
    global move
    global status
    global tic
    status = False
    keypress = ['K_p', 'K_UP', 'K_LEFT', 'K_DOWN', 'K_RIGHT']
    labels = [1, 2, 3, 4, 5]
    commands = ['p', 'w', 'r', 'j', 's']
    text = ['S', 'Up', 'Left', 'Down', 'Right']
    if keys[K_q]:
       status = True
       return targets, status            
    else:
       for i, j, k, g in zip(keypress, labels, commands, text):
           cmd = compile('cond = keys['+i+']', '<string>', 'exec')
           exec cmd
           if cond:
              move = g
              targets.append(j)
              send_command(k)
              break
    send_command('p')
    return targets, status


targetProcess = multiprocessing.Process(target=getKeyPress)
targetProcess.daemon = True
targetProcess.start()

if __name__ == '__main__': 
   import pygame
   pygame.init()
   w = 288
   h = 352
   size=(w,h)
   screen = pygame.display.set_mode(size)
   c = pygame.time.Clock() # create a clock object for timing
   pygame.display.set_caption('Driver')
   ubuntu = pygame.font.match_font('Ubuntu')
   font = pygame.font.Font(ubuntu, 13)
   inputs = []
   try:
     while not status:
           urllib.urlretrieve("http://192.168.0.10:8080/shot.jpg", "input.jpg")
           try:
             inputX = mpimg.imread('input.jpg')
           except IOError:
             status = True
           inputX = rgb2gray(inputX)/255
           out = inputX.copy()
           out = scipy.misc.imresize(out, (352, 288), interp='bicubic', mode=None)
           scipy.misc.imsave('input.png', out)
           inputs = processImages(inputX, inputs)
           print inputs.shape[1]
           img=pygame.image.load('input.png')
           screen.blit(img,(0,0))
           pygame.display.flip() 
           c.tick(1)
           if move != None:
              text = font.render(move, False, (255, 128, 255), (0, 0, 0))
              textRect = text.get_rect()
              textRect.centerx = 20 #screen.get_rect().centerx
              textRect.centery = 20 #screen.get_rect().centery
              screen.blit(text, textRect)
              pygame.display.update()
           if status:
              targetProcess.join()
              sio.savemat('inputs.mat', {'inputs':inputs})
   except KeyboardInterrupt:
     targetProcess.join()
     sio.savemat('inputs.mat', {'inputs':inputs})

   targetProcess.join()
   sio.savemat('inputs.mat', {'inputs':inputs})

提前致谢。

4

2 回答 2

1

我个人建议在不使用multiprocessing模块的情况下编写此代码:它使用fork()which 对大多数复杂库具有未指定的效果,例如在这种情况下pygame

您应该尝试将其编写为两个完全独立的程序。它迫使您考虑需要从一个到另一个的数据,这既是坏事也是好事(因为它可以澄清事情)。您可以使用一些进程间通信工具,例如 stdin/stdout 管道;例如,在一个程序(“主”程序)中,您将另一个程序作为子进程启动,如下所示:

popen = subprocess.Popen([sys.executable, '-u', 'my_subproc.py'],
                         stdin=subprocess.PIPE, stdout=subprocess.PIPE)

(这-u是无缓冲的。)

然后将数据读/写到父进程中的popen.stdin/popen.stdout,以及子进程中的sys.stdin/sys.stdout。最简单的例子是如果两个进程只需要一个同步信号,例如父进程在循环中等待子进程说“请下一个”。为此,子进程执行此操作print 'next please',而父进程执行此操作popen.stdin.readline()。(打印到子进程中的 sys.stdin。)

无关小记:

keypress = ['K_p', ...]
...
cmd = compile('cond = keys['+i+']', '<string>', 'exec')
exec cmd
if cond:

这看起来像是非常繁重的代码:

keypress = [K_p, ...]     # not strings, directly the values
...
if keys[i]:
于 2013-04-10T15:04:10.783 回答
0

我的建议是使用单独的线程。

#At the beginning
import threading

#Instead of def getKeyPress()
class getKeyPress(threading.Thread):
    def run(self):
        import pygame
        pygame.init()
        global targets
        global status
        while not status:
               pygame.event.pump()
               keys = pygame.key.get_pressed()
               targets, status = processOutputs(targets, keys)
        targets = np.array(targets)
        targets = flattenMatrix(targets)
        sio.savemat('targets.mat', {'targets':targets}) 

#Instead of 
#targetProcess = multiprocessing.Process(target=getKeyPress)
#targetProcess.daemon = True
#targetProcess.start()  
gkp = getKeyPress()
gkp.start()

另一种方法是创建两个不同的脚本并使用套接字来处理进程间通信。

于 2013-04-12T10:27:50.490 回答