简体   繁体   中英

What is the problem with buttons connection in PyQt5?

I have the problem that I cannot connect the implementation between two buttons. After I pressed the "Grayscale" button and got the grayscale image, I pressed the "Canny" button but the user interface suddenly closed. I don't know what's wrong in my code.

def getImage(self):
    global fname
    fname = QFileDialog.getOpenFileName(self, 'Open file', 
       'C:\\Users\binil-ping\Desktop\CODE',"Image Files (*.jpg *.gif *.bmp *.png)")
    pixmap = QPixmap(fname[0])
    self.label.setPixmap(QPixmap(pixmap))
    self.resize(pixmap.width(), pixmap.height())

def Grayscale(self):
    global edges
    edges = cv2.imread(fname[0], 0)
    edges = cv2.GaussianBlur(edges, (5, 5), 0)
    height, width = edges.shape[:2]
    ret,edges = cv2.threshold(edges,150,255,cv2.THRESH_BINARY)
    kernel = np.ones((5,5),np.uint8)
    edges = cv2.morphologyEx(edges, cv2.MORPH_OPEN, kernel)
    edges = cv2.morphologyEx(edges, cv2.MORPH_OPEN, kernel)

    edges = QImage(edges, width, height, QImage.Format_Grayscale8)
    pixmap = QPixmap.fromImage(edges)
    self.label.setPixmap(pixmap)
    self.resize(pixmap.width(), pixmap.height())

def Canny(self):
    edges2 = cv2.imread(edges[0],-1)
    edges2 = cv2.Canny(edges2,180,200)

    edges2 = QImage(edges2, width, height, QImage.Format_Grayscale8)
    pixmap = QPixmap.fromImage(edges2)
    self.label.setPixmap(pixmap)
    self.resize(pixmap.width(), pixmap.height())

在此处输入图像描述

There are a lot of problems with your code (including the fact that you didn't provide a minimal, reproducible example ), some of them explaining the crash or possibly leading to another one (I've marked them with [*]):

  • as already pointed out, avoid using globals whenever possible (which is almost always), use class attributes instead;
  • you are continuously overwriting those globals, making everything very confusing also for debugging; in fact you're using edges for both a numpy array and a QImage;
  • [*] you are trying to cv2.imread(edges[0],-1) , but not only imread expects a string, but, as a result of the previous point, at that point edges is even a QImage;
  • [*] some variables are not declared in the scope of the function (width/height in the Canny function);
  • you should really avoid using capitalized names for functions and variables, as they are usually only for class names and builtin constants;
  • there are some issues in the conversion back to QImage, I suppose that's due to the various transformations you're applying to to the array (some of them also seem unnecessary) that are not very friendly with the Format_Grayscale8 format, perhaps you should better investigate about that;

Here's a possible improvement over your code. I'm adding the widget creation parts, as it was missing in the original example.

class ShowImage(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        layout = QVBoxLayout(self)
        self.label = QLabel()
        layout.addWidget(self.label)

        self.getImageBtn = QPushButton()
        layout.addWidget(self.getImageBtn)
        self.getImageBtn.clicked.connect(self.getImage)

        self.grayBtn = QPushButton('gray')
        layout.addWidget(self.grayBtn)
        self.grayBtn.clicked.connect(self.grayScale)

        self.cannyBtn = QPushButton('canny')
        layout.addWidget(self.cannyBtn)
        self.cannyBtn.clicked.connect(self.canny)

        self.fileName = None
        self.edges = None

    def getImage(self):
        fname = QFileDialog.getOpenFileName(self, 'Open file', 
           'C:\\Users\binil-ping\Desktop\CODE',"Image Files (*.jpg *.gif *.bmp *.png)")
        if fname[0]:
            self.fileName = fname[0]
            pixmap = QPixmap(self.fileName)
            self.label.setPixmap(pixmap)

    def grayScale(self):
        if not self.fileName:
            return
        edges = cv2.imread(self.fileName, 0)
        edges = cv2.GaussianBlur(edges, (5, 5), 0)
        ret,edges = cv2.threshold(edges, 150, 255, cv2.THRESH_BINARY)
        kernel = np.ones((5, 5), np.uint8)
        edges = cv2.morphologyEx(edges, cv2.MORPH_OPEN, kernel)
        edges = cv2.morphologyEx(edges, cv2.MORPH_OPEN, kernel)

        self.edges = edges
        height, width = edges.shape[:2]
        image = QImage(edges, width, height, QImage.Format_Grayscale8)
        pixmap = QPixmap.fromImage(image)
        self.label.setPixmap(pixmap)

    def canny(self):
        if self.edges is None:
            return
        edges2 = cv2.Canny(self.edges, 180, 200)
        height, width = edges2.shape[:2]

        edges2 = QImage(edges2, width, height, QImage.Format_Grayscale8)
        pixmap = QPixmap.fromImage(edges2)
        self.label.setPixmap(pixmap)

Rule #1: Don't use globals.

Now on to the real answer.

PyQt has this really, really bad, annoying habit of just crashing if you have an uncaught exception in your code. That makes it hard to debug. Personally, I use a decorator around slots when debugging, which print my exception before PyQt can kill the application.

import logging
from functools import wraps
logger = logging.getLogger(__name__)
# ...lots of other code...
def debugFunc(*errors):
    def decorator(func):
        @wraps(func)
        def runner(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except errors as err:
                logger.debug(f"Function {func.__name__} raised a {err.__class__.__name__}, which was ignored.",
                             exc_info=True)
            except Exception as err:
                logger.critical(f"{err.__class__.__name__} - {err}", exc_info=True)
        return runner
    return decorator

While debugging, this allows me to ignore certain errors, and sends all others to the logging system. If you don't use it yourself and aren't willing to start using it, you can instead import traceback and use it's functions, instead of my calls to my logger object.

Just use this function as the innermost decorator, like this:

@debugFunc()
def Canny(self):
    edges2 = cv2.imread(edges[0],-1)
    edges2 = cv2.Canny(edges2,180,200)

    edges2 = QImage(edges2, width, height, QImage.Format_Grayscale8)
    pixmap = QPixmap.fromImage(edges2)
    self.label.setPixmap(pixmap)
    self.resize(pixmap.width(), pixmap.height())[enter image description here][1]

While I'm not familiar enough with cv2 to say for sure, I think your problem may be cv2.Canny. It doesn't look like the naming of other cv2 functions, and may cause an AttributeError if I'm right.

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