我正在使用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
模块。
答案 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