How to call a parent variable in a nested function

117 Views Asked by At

I've written a denoising function with cv2 and concurrent.futures, to be applied on both my training and test image data.

The functions (at current) are as follows:

def denoise_single_image(img_path):
    nonlocal data
    img = cv2.imread(f'../data/jpeg/{data}/{img_path}')
    dst = cv2.fastNlMeansDenoising(img, 10,10,7,21)
    cv2.imwrite(f'../processed_data/jpeg/{data}/{img_path}', dst)
    print(f'{img_path} denoised.')
 
def denoise(data):
    img_list = os.listdir(f'../data/jpeg/{data}')
    with concurrent.futures.ProcessPoolExecutor() as executor:
        tqdm.tqdm(executor.map(denoise_single_image, img_list))

data is to be either train or test, as necessary; img_list is a list of all image names in that directory.

I need to create the denoise_single_image() function before denoise(), otherwise denoise() won't recognize it; but I need to define data before I create denoise_single_image(). This seems to be a catch-22, unless I can figure out how to tell denoise_single_image() to refer to a variable that exists one level up.

nonlocal doesn't work because it assumes that data has already been defined in this environment. Is there any way to get this to work?

1

There are 1 best solutions below

0
On BEST ANSWER

You can change the iterable in executor.map to be a tuple of arguments, which can then split in your other function.

executor.map(denoise_single_image, ((img_path, data) for img_path in img_list))

def denoise_single_image(inputs):
    img_path, data = inputs
    # etc

But in your case I would just modify the individual image paths like so

executor.map(denoise_single_image, (f'jpeg/{data}/{img_path}' for img_path in img_list))

def denoise_single_image(img_path):
    img = cv2.imread(f'../data/{img_path}')
    dst = cv2.fastNlMeansDenoising(img, 10,10,7,21)
    cv2.imwrite(f'../processed_data/{img_path}', dst)
    print(f'{img_path.split('/')[-1]} denoised.')