OpenCV返回关键点的python多进程问题

时间:2019-01-17 21:55:59

标签: python opencv pickle multiprocess

我正在使用multiprocess Python模块将处理与OpenCV算法(例如ORB检测器/描述符)并行化。 multiprocess模块在​​大多数情况下都能正常工作,但是在返回cv2.KeyPoint对象列表时会出现问题-当返回到调用者进程时,每个关键点的所有字段都设置为0,尽管在工作进程内部,所有关键点都是正确的(由OpenCV返回)。

以下是可用于重现错误的最小示例(您将需要一个名为lena.png的图像文件才能使其工作):

import numpy as np

from cv2 import ORB_create, imread, cvtColor, COLOR_BGR2GRAY
from multiprocess import Pool

feature = ORB_create(nfeatures=4)

def proc(img):
    return feature.detect(img)

def good(feat, frames):
    return map(proc, frames)

def bad(feat, frames):
    # this starts a worker process
    # and then collects result
    # but something is lost on the way
    pool = Pool(4)
    return pool.map(proc, frames)

if __name__ == '__main__':
    # it doesn't matter how many images
    # a list of images is required to make use of
    # pool from multiprocess module
    rgb_images = map(lambda fn: imread(fn), ['lena.png'])
    grey_images = map(lambda img: cvtColor(img, COLOR_BGR2GRAY), rgb_images)
    good_kp = good(feature, grey_images)
    bad_kp = bad(feature, grey_images)

    # this will fail because elements in
    # bad_kp will all contain zeros
    for i in range(len(grey_images)):
    for x, y in zip(good_kp[i], bad_kp[i]):
            # these should be the same
            print('good: pt=%s angle=%s size=%s - bad: pt=%s angle=%s size=%s' % (x.pt, x.angle, x.size, y.pt, y.angle, y.size))
            assert x.pt == y.pt

平台:CentOS 7.6和Windows 10 x64

版本:

  • Python版本:2.7.15

  • 多进程:0.70.6.1

  • opencv-python-headless:3.4.5.20和4.0.0.21

是否有解决此问题的方法?由于大量使用lambda和“无法腌制”的可调用对象,因此无法选择使用标准multiprocessing模块。

1 个答案:

答案 0 :(得分:0)

经过分析,结果表明问题是由cv2.KeyPoint类引起的。在相关的question和相应的answer中建议这样做。问题在于pickle显然使用的dill无法与此类一起使用。

一个简单的解决方案是避免在工作进程和主进程之间发送cv2.KeyPoint的实例。如果这样做不方便,则应将每个关键点的数据包装在简单的Python结构或字典中并传递。

包装器的示例可能是:

import cv2
class KeyPoint(object):

    def __init__(self, kp):
        # type: (cv2.KeyPoint) -> None
        x, y = kp.pt
        self.pt = float(x), float(y)
        self.angle = float(kp.angle) if kp.angle is not None else None
        self.size = float(kp.size) if kp.size is not None else None
        self.response = float(kp.response) if kp.response is not None else None
        self.class_id = int(kp.class_id) if kp.class_id is not None else None
        self.octave = int(kp.octave) if kp.octave is not None else None

   def to_opencv(self):
        # type: () -> cv2.KeyPoint
        kp = cv2.KeyPoint()
        kp.pt = self.pt
        kp.angle = self.angle
        kp.size = self.size
        kp.response = self.response
        kp.octave = self.octave
        kp.class_id = self.class_id
        return kp