2

I would like to use multiprocessing to compute the SIFT extraction and SIFT matching for object detection. For now, I have a problem with the return value of the function that does not insert data in the dictionary. I'm using Manager class and image that are open inside the function. But does not work. Finally, my idea is: Computer the keypoint for every reference image, use this keypoint as a parameter of a second function that compares and match with the keypoint and descriptors of the test image.

My code is:

# %% Import Section
import cv2
import numpy as np
from matplotlib import pyplot as plt
import os
from datetime import datetime
from multiprocessing import Process, cpu_count, Manager, Lock
import argparse
# %% path section
tests_path = 'TestImages/'
references_path = 'ReferenceImages2/'
result_path = 'ResultParametrizer/'
#%% Number of processor
cpus = cpu_count()
# %% parameter section
eps = 1e-7
useTwo = False  # using the m and n keypoint better with False
# good point parameters
distanca_coefficient = 0.75
# gms parameter
gms_thresholdFactor = 3
gms_withRotation = True
gms_withScale = True
# flann parameter
flann_trees = 5
flann_checks = 50

#%% Locker
lock = Lock()

# %% function definition
def keypointToDictionaries(keypoint):
    x, y = keypoint.pt
    pt = float(x), float(y)
    angle = float(keypoint.angle) if keypoint.angle is not None else None
    size = float(keypoint.size) if keypoint.size is not None else None
    response = float(keypoint.response) if keypoint.response is not None else None
    class_id = int(keypoint.class_id) if keypoint.class_id is not None else None
    octave = int(keypoint.octave) if keypoint.octave is not None else None
    return {
        'point': pt,
        'angle': angle,
        'size': size,
        'response': response,
        'class_id': class_id,
        'octave': octave
    }

def dictionariesToKeypoint(dictionary):
    kp = cv2.KeyPoint()
    kp.pt = dictionary['pt']
    kp.angle = dictionary['angle']
    kp.size = dictionary['size']
    kp.response = dictionary['response']
    kp.octave = dictionary['octave']
    kp.class_id = dictionary['class_id']
    return kp

def rootSIFT(dictionary, image_name, image_path,eps=eps):
    # SIFT init
    image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    sift = cv2.xfeatures2d.SIFT_create()
    keypoints, descriptors = sift.detectAndCompute(image, None)
    descriptors /= (descriptors.sum(axis=1, keepdims=True) + eps)
    descriptors = np.sqrt(descriptors)
    print('Finito di calcolare, PID: ', os.getpid())
    lock.acquire()
    dictionary[image_name]['keypoints'] = keypoints
    dictionary[image_name]['descriptors'] = descriptors
    lock.release()


def featureMatching(reference_image, reference_descriptors, reference_keypoints, test_image, test_descriptors,
                    test_keypoints, flann_trees=flann_trees, flann_checks=flann_checks):
    # FLANN parameter
    FLANN_INDEX_KDTREE = 1
    index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=flann_trees)
    search_params = dict(checks=flann_checks)  # or pass empty dictionary
    flann = cv2.FlannBasedMatcher(index_params, search_params)
    flann_matches = flann.knnMatch(reference_descriptors, test_descriptors, k=2)
    matches_copy = []
    for i, (m, n) in enumerate(flann_matches):
        if m.distance < distanca_coefficient * n.distance:
            matches_copy.append(m)
    gsm_matches = cv2.xfeatures2d.matchGMS(reference_image.shape, test_image.shape, keypoints1=reference_keypoints,
                                           keypoints2=test_keypoints, matches1to2=matches_copy,
                                           withRotation=gms_withRotation, withScale=gms_withScale,
                                           thresholdFactor=gms_thresholdFactor)
#%% Starting reference list file creation
reference_init = datetime.now()
print('Start reference file list creation')
reference_image_process_list = []
manager = Manager()
reference_image_dictionary = manager.dict()
reference_image_list = manager.list()
for root, directories, files in os.walk(references_path):
    for file in files:
        if file.endswith('.DS_Store'):
            continue
        reference_image_path = os.path.join(root, file)
        reference_name = file.split('.')[0]
        image = cv2.imread(reference_image_path, cv2.IMREAD_GRAYSCALE)
        reference_image_dictionary[reference_name] = {
            'image': image,
            'keypoints': None,
            'descriptors': None
        }
        proc = Process(target=rootSIFT, args=(reference_image_list, reference_name, reference_image_path))
        reference_image_process_list.append(proc)
        proc.start()


for proc in reference_image_process_list:
    proc.join()


reference_end = datetime.now()
reference_time = reference_end - reference_init
print('End reference file list creation, time required: ', reference_time)
my_most
  • 21
  • 1

1 Answers1

0

I faced pretty much the same error. It seems that the code hangs at detectAndCompute in my case, not when creating the dictionary. For some reason, sift feature extraction is not multi-processing safe (to my understanding, it is the case in Macs but I am not totally sure.)

I found this in a github thread. Many people say it works but I couldn't get it worked. (Edit: I tried this later which works fine)

Instead I used multithreading which is pretty much the same code and works perfectly. Of course you need to take multithreading vs multiprocessing into account

smttsp
  • 4,011
  • 3
  • 33
  • 62