Многопроцессная проблема Python с возвратом ключевых точек OpenCV - PullRequest
0 голосов
/ 18 января 2019

Я использую 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

Есть ли способ обойти это? Использование стандартного модуля multiprocessing не допускается из-за интенсивного использования лямбд и вызываемых предметов, которые «не могут быть засолены».

1 Ответ

0 голосов
/ 31 января 2019

После некоторого анализа выяснилось, что проблема вызвана чем-то около класса cv2.KeyPoint. Это предлагается в связанном вопросе и соответствующем ответе . Проблема в том, что 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
...