简体   繁体   中英

Trying to add a function with returns to a button command in Tkinter

I'm developing a 3D reconstruction from video App, but I never used Tkinter in my life and I never finished a code using OOP, and what I know about OOP is in java, not python, so you can imagine I'm a bit lost.

I have a Class that is used for camera calibration and I have a method that does camera calibration and works properly, I already tested it.

My problem is that the camera calibration method has returns in it, quite a lot, actually, and I don't know how to store the returns. Can you help me with this?

class CamCalib(tk.Frame):

# Auto-Calibração da Câmera
def calibrate(dirpath, prefix, image_format, square_size, width=9, height=6):
    """ Apply camera calibration operation for images in the given directory path. """
    # prepare object points, like (0,0,0), (1,0,0), (2,0,0), ..., (8,6,0)
    criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)

    objp = np.zeros((height * width, 3), np.float32)
    objp[:, :2] = np.mgrid[0:width, 0:height].T.reshape(-1, 2)
    objp = objp * square_size
    # if square_size is 1.5 centimeters, it would be better to write it as 0.015 meters. Meter is a better metric because most of the time we are working on meter level projects.
    # Arrays to store object points and image points from all the images.
    objpoints = []  # 3d point in real world space
    imgpoints = []  # 2d points in image plane.

    images = glob.glob(dirpath + '/' + prefix + '*.' + image_format)

    for fname in images:
        img = cv.imread(fname)
        gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        # Find the chess board corners
        ret, corners = cv.findChessboardCorners(gray, (width, height), None)
        # If found, add object points, image points (after refining them)
        if ret:
            objpoints.append(objp)
            corners2 = cv.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
            imgpoints.append(corners2)
            # Draw and display the corners
            img = cv.drawChessboardCorners(img, (width, height), corners2, ret)
        #     cv.imshow('img', cv.resize(img, (800, 1400)))
        #     cv.waitKey()
        # cv.destroyAllWindows()
    ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

    return [ret, mtx, dist, rvecs, tvecs]

def save_coefficients(mtx, dist, path):
    """ Save the camera matrix and the distortion coefficients to given path/file. """
    cv_file = cv.FileStorage(path, cv.FILE_STORAGE_WRITE)
    cv_file.write("K", mtx)
    cv_file.write("D", dist)
    # note you *release* you don't close() a FileStorage object
    cv_file.release()

def load_coefficients(path):
    """ Loads camera matrix and distortion coefficients. """
    # FILE_STORAGE_READ
    cv_file = cv.FileStorage(path, cv.FILE_STORAGE_READ)

    # note we also have to specify the type to retrieve other wise we only get a
    # FileNode object back instead of a matrix
    camera_matrix = cv_file.getNode("K").mat()
    dist_matrix = cv_file.getNode("D").mat()

    cv_file.release()
    return [camera_matrix, dist_matrix]

def browse_button(self):
    # Allow user to select a directory and store it in global var
    # called folder_path
    self.filename = filedialog.askdirectory()

def __init__(self, parent, controller):

    # Calibration Variables


    # Tkinter page config
    tk.Frame.__init__(self, parent)
    self.filename = ""
    rb_var = tk.StringVar()
    ph = tk.Label(self, text="                                   ")
    label1 = tk.Label(self, text="Calibração de Câmera", font=LARGE_BOLD_FONT)
    label3 = tk.Label(self, textvariable=self.filename, font=LARGE_FONT)
    entry1 = ttk.Entry(self, width=30)
    label2 = tk.Label(self, text="Selecione o diretório das imagens para realizar a Calibração de Câmera: ", font=LARGE_FONT)
    b1 = ttk.Button(self, text="Browse", command=TCCapp.combine_funcs(self.browse_button, lambda: label3.config(text=(self.filename))))
    ph1 = tk.Label(self, text="                                   ")
    label4 = tk.Label(self, text="Prefixo em comum das imagens no diretório (Ex: imagem1.jpg, imagem2.jpg -> Prefixo = imagem): ", font=LARGE_FONT)
    b3 = ttk.Button(self, text="Voltar", command=TCCapp.combine_funcs(lambda: controller.show_frame(StartPage), lambda: entry1.delete(0, tk.END)))
    label5 = tk.Label(self, text="Formato da imagem: ", font=LARGE_FONT)
    radio1 = ttk.Radiobutton(self, text="jpg/jpeg", variable=rb_var, value="jpg")
    radio2 = ttk.Radiobutton(self, text="png", variable=rb_var, value="png")
    label6 = tk.Label(self, text="Tamanho de um quadrado na folha quadriculada (Ex: Insira 2.5 para 2,5cm, por exemplo): ", font=LARGE_FONT)
    entry2 = ttk.Entry(self, width=30)
    b2 = ttk.Button(self, text="Iniciar",
                    command=TCCapp.combine_funcs(lambda: self.calibrate(dirpath=self.filename, prefix=entry1.get(), image_format=str(rb_var), square_size=float(entry2.get())/100)))

    # Grid Organizer
    ph.grid(row=0, column=0)
    ph1.grid(row=1, column=4)
    b1.grid(row=1, column=3)
    b2.grid(row=6, column=3, sticky="nsw")
    b3.grid(row=6, column=3, sticky="nse")
    entry1.grid(row=3, column=3)
    entry2.grid(row=5, column=3)
    label1.grid(row=0, column=2)
    label2.grid(row=1, column=2, sticky="nse")
    label3.grid(row=2, column=2, sticky="nsew")
    label4.grid(row=3, column=2)
    label5.grid(row=4, column=2, sticky="nse")
    label6.grid(row=5, column=2, sticky="nse")
    radio1.grid(row=4, column=3, sticky="nsw")
    radio2.grid(row=4, column=3, sticky="nse")

This is the entire Class. As you can see, the method calibrate has 5 variables as returns from it. I already did something similar with self.filename = "" but I don't know all datatypes from the variables that I need to return. b2 is the button that is calling the calibrate method inside a combine_funcs that I use to call multiple functions inside a single button (you can ignore it, I placed it there just in case I want to do multiple things with that button).

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.2032.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 1895, in __call__
    return self.func(*args)
  File "C:/Users/v_i_b/PycharmProjects/TCC/main.py", line 44, in combined_func
    f(*args, **kwargs)
  File "C:/Users/v_i_b/PycharmProjects/TCC/main.py", line 153, in <lambda>
    command=TCCapp.combine_funcs(lambda: self.calibrate(dirpath=self.filename, prefix=entry1.get(), image_format=str(rb_var), square_size=float(entry2.get())/100)))
TypeError: calibrate() got multiple values for argument 'dirpath'

Thanks for your time!

You can just make up a function like button_pressed() and you can make it trigger the calibrate function.

For example when you press the button b2 it calls the function button_pressed() then the button_pressed() calls calibrate()

def button_pressed():
    values_stored = calibrate()

Then you can use your stored values.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM