-1

I'm learning opencv and to make it easy for me to not have to scroll through hundreds of lines of code, I've made two files named file1.py and file2.py.

All the functions I want to use are in file1.py and I'm calling them from file2.py. Functions in file1.py are:

def main(title="Test", func=None):

    global img, original_img

    cv2.namedWindow(title)

    cv2.setMouseCallback(title, func)

    while True:
        cv2.imshow(title, img)

        if func == draw_shape:
            k = cv2.waitKey(1)
            if k == ord('m') or k == ord('M'):
                shape = not shape
            elif k == 27:
                break
        else:
            if cv2.waitKey(1) == 27:
                break

    cv2.destroyWindow(title)

def draw_shape(event, x, y, flags, param):
    global ix, iy, shape, drawing, fill, img, original_img

    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        ix, iy = x, y
    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing:
            if shape:
                cv2.rectangle(img, (ix, iy), (x, y), (0, 244, 0), fill)
            elif not shape:
                cv2.circle(img, (x, y), 20, (0, 0, 244), fill)
    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        img = deepcopy(original_img)

There's a lot more code having same problem (which I'll explain in a moment) in file1.py which I omitted for sake of space.

I know I can modify main() and pass img to it but the problem starts at draw_shape() which is associated with cv2.setMouseCallback and gets called automatically. So I can't just pass variables, like ix, drawing etc. which, when I was calling main() in file1.py itself, were global in that case, to draw_shape() myself.

But now as I've made file2.py and I want to call main() from there, I'm not able to pass those variables anymore.

The code in file2.py is as:

from file1 import main, draw_shape

if __name__ == "__main__":
    imagepath = "some\path\someImage.jpg"
    img = cv2.imread(imagepath, 0)
    original_img = deepcopy(img)
    ix, iy, fill = (-1, -1, 0)
    shape, drawing = True, False
    main(title='XYZ', func=draw_shape)

Any suggestions how I could make main() and draw_shape() to use variables, I've declared by the same names as required by them, from file2.py (or if any other way to pass variables to them)?

  • As far I understood, you define some variables in file2 (`img`, `original_img`) and these should be seen as globals by functions in file1, which is imported in file2. If this is correct, [this question](https://stackoverflow.com/questions/13034496/using-global-variables-between-files) may be helpful. – Valentino Feb 16 '19 at 16:00
  • 1
    BTW, a good [mcve] should have the shortest possible code that reproduces your problem -- every single line that isn't specifically required to showcase your question should be removed. – Charles Duffy Feb 16 '19 at 16:02
  • I've already done that Charles. main() put up there is not even half the actual one – Abhishek Kwatra Feb 16 '19 at 17:57
  • I did look that question Valentino, and it did work. But I don't think it'll be a good practice to learn about, as doing it that way, I'd have to rewrite newFile.variable in place of every actual variable in file1. Which, to me seems like: a violation of DRY, and a makeshift way to solve my problem. Moreover it also doesn't feel like a pythonic way. Don't you think so? – Abhishek Kwatra Feb 16 '19 at 18:05
  • imho, I don't think is a violation of DRY. It just make clear where a variable is defined. It's also what [the docs](https://docs.python.org/3/faq/programming.html#how-do-i-share-global-variables-across-modules) recommend. – Valentino Feb 16 '19 at 19:29

2 Answers2

0

Python packaging allows you to import files from another file using:

from python_package import function

However, the more pythonic way is to put it on the same file.

You can read more on packages and modules in Python - here.

Jab
  • 26,853
  • 21
  • 75
  • 114
hodisr
  • 314
  • 2
  • 12
  • Pardon, but I know how to import functions from another package. But that's not the problem. Problem is that functions in file1.py are using some global variables which I don't know how to pass from file2.py – Abhishek Kwatra Feb 16 '19 at 15:45
  • Pass the image as an [argument](https://stackoverflow.com/questions/706721/how-do-i-pass-a-method-as-a-parameter-in-python) – Jab Feb 16 '19 at 15:51
  • Still, my problem won't be solved as I can't pass arguments to draw_shape() myself. – Abhishek Kwatra Feb 16 '19 at 15:53
0

If this is how you’re structuring your code you will need to do the following

#file1.py
#add image as an argument
def main(title = "Test", func = None, image = None):
    ...

#file2.py
from file2 import main

...

main(title = 'XYZ', image = img)

But like hodiser said. Just put them in one file, you’d end up having hundreds if not thousands of files with just a paragraphs length of code in them.

Jab
  • 26,853
  • 21
  • 75
  • 114
  • That will make only the main() function to work correctly but draw_shape, which gets called by cv2.setMouseCallback(), will not be able to access that img. And that's not all the code in file1.py. It contains approximately 300 lines of code, and it's still growing (which is the exact reason I split the code) – Abhishek Kwatra Feb 16 '19 at 18:14