1

I have the following source code in main.py

main.py

import data_utils as du

X_train1, Y_train1, groundtruth_train1= du.loaddata(train_file, "adjust_gamma", 0.8)
X_train2, Y_train2, groundtruth_train2= du.loaddata(train_file, "adjust_gamma", 1.2)
X_train3, Y_train3, groundtruth_train3= du.loaddata(train_file, "scale_image", 0.5)
X_train4, Y_train4, groundtruth_train4= du.loaddata(train_file, "scale_image", 0.8)
X_train5, Y_train5, groundtruth_train5= du.loaddata(train_file, "scale_image", 1.5)
X_train6, Y_train6, groundtruth_train6= du.loaddata(train_file, "scale_image", 2.0)
X_train7, Y_train7, groundtruth_train7= du.loaddata(train_file, "compress_jpeg", 70)
X_train8, Y_train8, groundtruth_train8= du.loaddata(train_file, "compress_jpeg", 90)

main.py will read several images, apply image transformations, divide them into blocks (these are my X_train outputs) and get the images labels (Y_train and groundtruth_train). The image transform is defined by a string with parameters (e.g., "adjust_gamma", etc.).

Now, load_data.py was built inspired on this answer about how to pass functions with arguments to another function

data_utils.py

def loaddata(file_images, function_name, parameter):

x = []
y = []

with open(file_images) as f:
    images_names = f.readlines()
    images_names = [a.strip() for a in images_names]

    j=0

    for line in images_names:

        j=j+1

        line='image_folder/' + line
        img = cv2.imread(img_path)
        img=perform(eval(function_name)(img,parameter)) 
        ...

The function performs will receive the function name (as string as you can see in the main.py) and its parameters (image in numpy array and parameters). The function performed is detailed below:

def perform(fun, *args):
fun(*args)

def adjust_gamma(image, gamma):
   invGamma = 1.0 / gamma
   table = np.array([((i / 255.0) ** invGamma) * 255
      for i in np.arange(0, 256)]).astype("uint8")
   return cv2.LUT(image, table)

def compress_jpeg(image, compression_factor):
   encode_param=[int(cv2.IMWRITE_JPEG_QUALITY), compression_factor]
   result, encimg=cv2.imencode('.jpg', image, encode_param)
   decimg=cv2.imdecode(encimg, 1)
   return decimg

def scale_image(image, scaling_factor):
   resized_image=cv2.resize(image, (scaling_factor, scaling_factor))
   return resized_image 

I tried to use eval function so the string passed could be regarded as a function name(This answer inspired me to do that). However, when I run the code I get the following error:

File "main.py", line 32, in do_experiment

X_train1, Y_train1, groundtruth_train1= du.loaddata(train_file, "adjust_gamma", 0.8)

File "data_utils.py", line 29, in loaddata

img=perform(eval(function_name)(img,parameter)) File "data_utils.py",

line 171, in perform fun(**args) TypeError: 'numpy.ndarray' object is not callable

So, how can I solve my problem? how can I pass a function as arguments to another function by using the function name as a string?

Mehrdad Pedramfar
  • 10,941
  • 4
  • 38
  • 59
mad
  • 2,677
  • 8
  • 35
  • 78
  • 1
    Why do you use string aliases for functions instead of importing them? – Yossi Nov 21 '18 at 05:46
  • 1
    Your indentation seems to be off. Instead of have us guess what should be indented, please [edit] your question to show us exactly where each `def` ends. (On the desktop version of this site, copy-paste your code, select the pasted text, and type ctrl-K to have it indented.) – tripleee Nov 21 '18 at 05:49

1 Answers1

1

Replace eval(function_name)(img,parameter) with:

globals()[function_name](img,parameter)

Note that your desired function should be in the same module in my answer, if it is not, read this link or This about globals and locals in python to find the best thing for your problem.

Also, you can access a function of another module with getattr, like this:

getattr(module, func)(*args, **kwargs)
Mehrdad Pedramfar
  • 10,941
  • 4
  • 38
  • 59