Python multiprocessing queue is empty although it is filled in a different thread

删除回忆录丶 提交于 2021-01-28 07:33:04

问题


I have now tried to resolve this issue for multiple hours but no matter what I do, I never get the thing to work.

My project tracks live data and provides an endpoint for other services to get the latest(ish) measurement. But no matter what I do, the queue.get() always returns nothing.

Here is my code:

from collections import deque
import numpy as np
import argparse
import imutils
import cv2
from flask import Flask
from multiprocessing import Queue
import threading
import Queue as Q

app = Flask(__name__)


class ImageParser(object):
    def dosmth(self, q):
        ap = argparse.ArgumentParser()
        ap.add_argument("-v", "--video", help="path to the (optional) video file")
        ap.add_argument("-b", "--buffer", type=int, default=14, help="max buffer size")
        args = vars(ap.parse_args())

        greenLower = [(86, 61, 128)]
        greenUpper = [(148, 183, 196)]
        pts1 = deque(maxlen=args["buffer"])
        pts2 = deque(maxlen=args["buffer"])

        if not args.get("video", False):
            camera = cv2.VideoCapture(0)

        else:
            camera = cv2.VideoCapture(args["video"])

        while True:
            (grabbed, frame) = camera.read()

            if args.get("video") and not grabbed:
                break

            frame = imutils.resize(frame, width=1200)
            hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

            for j in range(len(greenLower)):
                upper = greenUpper[j]
                lower = greenLower[j]

                mask = cv2.inRange(hsv, lower, upper)
                mask = cv2.erode(mask, None, iterations=2)
                mask = cv2.dilate(mask, None, iterations=2)

                cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
                                        cv2.CHAIN_APPROX_SIMPLE)[-2]
                for i in range(len(cnts)):
                    center = None

                    if len(cnts) > 0:
                        c = max(cnts, key=cv2.contourArea)

                        ((x, y), radius) = cv2.minEnclosingCircle(c)
                        M = cv2.moments(c)
                        center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))

                        if radius > 10:
                            q.put(center)
                            cv2.circle(frame, (int(x), int(y)), int(radius),
                                       (0, 255, 255), 2)
                            cv2.circle(frame, center, 5, (0, 0, 255), -1)

                    if j == 0:
                        pts1.appendleft(center)
                        for i in xrange(1, len(pts1)):
                            if pts1[i - 1] is None or pts1[i] is None:
                                continue

                            thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
                            cv2.line(frame, pts1[i - 1], pts1[i], (255,0,0), thickness)

                    if j == 1:
                        pts2.appendleft(center)
                        for i in xrange(1, len(pts2)):
                            if pts2[i - 1] is None or pts2[i] is None:
                               continue

                            thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
                            cv2.line(frame, pts2[i - 1], pts2[i], (51, 153, 255), thickness)

            cv2.imshow("Frame", frame)
            key = cv2.waitKey(1) & 0xFF

            if key == ord("q"):
                break

        camera.release()
        cv2.destroyAllWindows()


imgPar = ImageParser()
q = Queue()
scp = threading.Thread(target=imgPar.dosmth, args=(q,))
scp.start()

def getVal():
    try:
        (x,y) = q.get_nowait()
    except Q.Empty:
        return -1 , -1
    return (x,y)

@app.route('/', methods=['GET'])
def doMain():
    x,y = getVal()
    print x,y
    return '{},{}'.format(x,y)

app.run(debug=True, host='10.21.8.52')

As I really do not have any other clue, what I should do, any help would be appreciated.

Everything is running on python 2.7.15 in an anaconda environment if that helps in any way.
As I really do not have


回答1:


I took the liberty of stripping out the CV2 code as I don't have a camera, and replace the queue filler with a pair of random numbers every .5 seconds, and PEP8-ing the code a bit, and this way it works:

import random
import time

from flask import Flask
import threading
from multiprocessing import Queue
from Queue import Empty as QueueEmpty

app = Flask(__name__)

class ImageParser(object):
    def __init__(self, queue):
        self.queue = queue
        self.source = random.random
        self.pause = 0.5

    def run(self):
        while True:
            value = (self.source(), self.source())
            self.queue.put(value)
            time.sleep(self.pause)

queue = Queue()
image_parser = ImageParser(queue)
image_thread = threading.Thread(target=image_parser.run)

@app.route('/', methods=['GET'])
def do_main():
    try:
        value = queue.get_nowait()
    except QueueEmpty:
        value = None
    print(value)
    return str(value)

if __name__ == '__main__':
    image_thread.start()
    app.run(debug=True, host='127.0.0.1')

Under http://127.0.0.1:5000/ I now get pairs of random numbers, and the occasional None when I reload too fast.

I therefore conclude that the problem probably lies with the image processing part. Specifically I noticed that only contours with an enclosing radius > 10 get put into the queue. Maybe that path of code just never gets executed. Are you quite sure that any values get put into the queue at all? Maybe a print x, y, radius before the if radius > 10 will shed some light. (And why put center instead of x and y?)



来源:https://stackoverflow.com/questions/53331297/python-multiprocessing-queue-is-empty-although-it-is-filled-in-a-different-threa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!