0

I return an image from function (find_defects). and I see that it is a valid image.

image which i want to show

I check image before return using cv2.imshow and it is also like i expected. But when i try to show this image on a GUI which i designed using PyQt, i see this error:

Process finished with exit code 1

EDIT: Minimum reproducible example:

from PyQt5.QtCore import *
import cv2
from PyQt5.QtWidgets import QLabel, QWidget, QPushButton, QVBoxLayout, QApplication
from PyQt5.QtGui import QPixmap, QImage


class first_GUI(QWidget):
    def __init__(self):
        # super(first_GUI, self).__init__()
        # super().__init__()
        QWidget.__init__(self)
        self.frame_defects = cv2.imread('output.jpg')
        self.label_text = QLabel("Hi")
        self.label_text.setAlignment(Qt.AlignCenter)
        self.label_text.setStyleSheet("color: rgb(0,0,255);font-weight: bold; font-size: 16pt")
        pushButton_show = QPushButton("Show")
        pushButton_show.setMinimumHeight(40)
        pushButton_show.setStyleSheet("font-weight: bold; font-size: 16pt")
        pushButton_show.clicked.connect(self.show_image)
        vertical_layout = QVBoxLayout()
        vertical_layout.addWidget(self.label_text)
        vertical_layout.addWidget(pushButton_show)
        self.setLayout(vertical_layout)
        self.setWindowTitle("PyQt5 first GUI")
        self.resize(400, 300)


    def show_image(self):

        if self.frame_defects is not None:
            image = QImage(self.frame_defects, self.frame_defects.shape[1], self.frame_defects.shape[0],
                           QImage.Format_RGB888)  # The image is stored using a 24-bit RGB format (8-8-8).
            self.pixmap2 = QPixmap.fromImage(image)
        self.label.setPixmap(self.pixmap2)

app = QApplication([])
widget = first_GUI()
widget.show()
app.exec_()  

image:

image

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Mustafa
  • 117
  • 1
  • 9
  • This image is very difficult to read. Please copy and paste the code instead – Damien Jan 31 '20 at 15:45
  • Also add `self.pixmap2 = QPixmap()` before `if ...` – eyllanesc Jan 31 '20 at 17:52
  • @Mustafa please use `@username`. change `image = QImage(...)` to `h, w, ch = self.frame_defects.shape` `bytesPerLine = ch * w` `image = QImage(self.frame_defects.data, w, h, bytesPerLine, QImage.Format_RGB888).rgbSwapped()` – eyllanesc Jan 31 '20 at 18:00
  • @Mustafa or change to `self.frame_defects = self.frame_defects[:,:,::-1]` `h, w, ch = self.frame_defects.shape bytesPerLine = ch * w image = QImage(self.frame_defects.data, w, h, bytesPerLine, QImage.Format_RGB888)` – eyllanesc Jan 31 '20 at 18:01
  • OpenCV by default uses the BGR format but Qt uses RGB so the blue color will appear as red and vice versa, so you must exchange the R with B. – eyllanesc Jan 31 '20 at 18:03
  • I prefer the second method since it is faster (check my other answer https://stackoverflow.com/a/55468544/6622587) – eyllanesc Jan 31 '20 at 18:04
  • @Mustafa As I have already pointed out: it is a duplicate of my previous answer, and practically the new "answer" has taken the corrections of my comments making its answer the same as my answer to the previous question. – eyllanesc Jan 31 '20 at 18:18

1 Answers1

0

Consider using QGraphicsView instead of a label.

# Create scene
self.image_item = QGraphicsPixmapItem()
scene = QGraphicsScene(self)
scene.addItem(self.image_item)

# Create GraphicView display
self.view = QGraphicsView(scene, self)
image = QImage(self.frame_defects, self.frame_defects.shape[1], self.frame_defects.shape[0], self.frame_defects.shape[1]*3, QImage.Format_RGB888)
self.image_item.setPixmap(QPixmap.fromImage(image))
self.view.fitInView(self.image_item)

Also notice that the dtype of self.frame_defects is 'uint8', and if you don't specify the bytesperline parameter in the QImage constructor it will be converted to 'uint32' or 'int32'. So in order to keep the bytes per line of your image, I used a different QImage constructor:

QImage(self.frame_defects, self.frame_defects.shape[1], self.frame_defects.shape[0], self.frame_defects.shape[1]*3, QImage.Format_RGB888)

Edit: I tried this code in my PyCharm, and it works:

from PyQt5.QtCore import *
import cv2
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *


class first_GUI(QWidget):
    def __init__(self):
        # super(first_GUI, self).__init__()
        # super().__init__()
        QWidget.__init__(self)
        self.frame_defects = cv2.imread('output.jpg')
        self.image_item = QGraphicsPixmapItem()
        scene = QGraphicsScene(self)
        scene.addItem(self.image_item)
        self.view = QGraphicsView(scene, self)

        pushButton_show = QPushButton("Show")
        pushButton_show.setMinimumHeight(40)
        pushButton_show.setStyleSheet("font-weight: bold; font-size: 16pt")
        pushButton_show.clicked.connect(self.show_image)

        vertical_layout = QVBoxLayout()
        vertical_layout.addWidget(self.view)
        vertical_layout.addWidget(pushButton_show)

        self.setLayout(vertical_layout)
        self.setWindowTitle("PyQt5 first GUI")
        self.resize(400, 300)

    def show_image(self):
        image = QImage(self.frame_defects, self.frame_defects.shape[1], self.frame_defects.shape[0], self.frame_defects.shape[1]*3, QImage.Format_RGB888)
        self.image_item.setPixmap(QPixmap.fromImage(image))
        self.view.fitInView(self.image_item)


app = QApplication([])
widget = first_GUI()
widget.show()
app.exec_()

edit2:

Add image = image.rgbSwapped() after the QImage constructor:

    def show_image(self):
    image = QImage(self.frame_defects, self.frame_defects.shape[1], self.frame_defects.shape[0], self.frame_defects.shape[1]*3, QImage.Format_RGB888)
    image = image.rgbSwapped()
    self.image_item.setPixmap(QPixmap.fromImage(image))
    self.view.fitInView(self.image_item)
kalzso
  • 502
  • 2
  • 6
  • 27
  • thx, but when i press button nothing happens. I updated code according to your answer – Mustafa Jan 31 '20 at 17:00
  • try to derive first_GUI from QMainWindow instead of QWidget like this: class first_GUI(QMainWindow): – kalzso Jan 31 '20 at 17:05
  • i tried, button doesn't show up – Mustafa Jan 31 '20 at 17:20
  • Okay, but don't change the code in the question if it's not working yet :) – kalzso Jan 31 '20 at 17:36
  • @kalzso Why do you recommend changing QWidget to QMainWindow? I don't see the logic in it. – eyllanesc Jan 31 '20 at 17:37
  • @kalzso `self.frame_defects.shape[1]*3`, Practically there is the key to the matter that is indicated in the duplicate: `h, w, ch = self.frame_defects.shape` `bytesPerLine = w * ch` where ch = 3 in this case :-) – eyllanesc Jan 31 '20 at 17:44
  • @kalzso i see [this](https://imgur.com/a/g2WegEd) result – Mustafa Jan 31 '20 at 17:54
  • @Mustafa **OR** 1) add `image = image.rgbSwapped()` after `image = QImage(...)` **OR** 2) add `self.frame_defects = self.frame_defects[:,:,::-1]` before `image = QImage(...)` – eyllanesc Jan 31 '20 at 17:58
  • @eyllanesc true, I updated my answer again, according to your addition. – kalzso Jan 31 '20 at 18:01
  • @kalzso I prefer the second method since it is faster (check my other answer https://stackoverflow.com/a/55468544/6622587) – eyllanesc Jan 31 '20 at 18:04