asmmahmud
asmmahmud

Reputation: 5054

QLabel is not updating the image after OpenCV image manipulation

I've been trying to create an interactive OpenCV image viewer where I'll be able to view the image immediately after a manipulation. Like say, I'm applying a binary thresholding operation on an image and changing the threshold value from PyQt slider. Now, I want to see each thresholded image in the image viewer.

I've created a very basic program for this purpose using python OpenCV and PyQT5 lib. But, the image is not being updated in the QLabel.

Below is my code:

import sys
import cv2
import numpy as np
import imutils
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout, QLCDNumber, QSlider, QLabel, QCheckBox
from PyQt5.QtGui import QPixmap, QImage


class MyWindow(QWidget):

def __init__(self):
    super().__init__()
    self.imglabel = QLabel(self)
    self.imglabel.setFixedSize(1200, 900)
    ori_img = cv2.imread("../resources/omr-1-ans-ori.png", cv2.IMREAD_COLOR)
    ori_img = imutils.resize(ori_img, height=960)
    self.gray_img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
    self.gray_img_c = ori_img

    self.thresh = False
    self.thresh_karnel_size = 11

    self.init_ui()

def init_ui(self):
    # lcd = QLCDNumber(self)
    hbox1 = QHBoxLayout()
    cb_thresh = QCheckBox('thresh', self)
    cb_thresh.setChecked(False)

    cb_thresh.stateChanged.connect(self.changeTitleThresh)
    hbox1.addWidget(cb_thresh)

    thresh_slider = QSlider(Qt.Horizontal, self)
    thresh_slider.setFocusPolicy(Qt.StrongFocus)
    thresh_slider.setTickPosition(QSlider.TicksBothSides)
    thresh_slider.setTickInterval(1)
    thresh_slider.setSingleStep(1)
    thresh_slider.setPageStep(1)
    thresh_slider.setMinimum(1)
    thresh_slider.setMaximum(127)
    thresh_slider.valueChanged[int].connect(self.threshSliderChangeValue)

    vbox = QVBoxLayout()
    vbox.addLayout(hbox1)
    vbox.addWidget(thresh_slider)
    vbox.addWidget(self.imglabel)
    self.setLayout(vbox)

    self.setGeometry(50, 50, 1200, 768)
    self.setWindowTitle('Learning PyQT5')
    self.updateImage()
    self.show()

def changeTitleThresh(self, state):
    # print("thresh checkbox: ", state, Qt.Checked)
    if state == Qt.Checked:
        self.thresh = True
    else:
        self.thresh = False

def threshSliderChangeValue(self, value):

    ksize = (value * 2) + 1
    print("ksize: ", ksize)
    if ksize > 1 and ksize % 2 != 0 and self.thresh:
        self.thresh_karnel_size = ksize
        self.gray_img = cv2.threshold(self.gray_img, self.thresh_karnel_size, 255, cv2.THRESH_BINARY)[1]
        self.gray_img_c = cv2.cvtColor(self.gray_img.copy(), cv2.COLOR_GRAY2BGR)
        self.updateImage()

def updateImage(self):

    height, width, channel = self.gray_img_c.shape
    bytesPerLine = 3 * width
    qImg = QImage(self.gray_img_c.data, width, height, bytesPerLine, QImage.Format_RGB888)
    pixMap = QPixmap.fromImage(qImg)
    pixMap = pixMap.scaled(700, 500, Qt.KeepAspectRatio)
    self.imglabel.setPixmap(pixMap)
    self.imglabel.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyWindow()
    sys.exit(app.exec_())

I've tried every solution found through google search. But, could not fix it. Any help or hint will be much appreciated.

Upvotes: 2

Views: 788

Answers (1)

eyllanesc
eyllanesc

Reputation: 244282

The original image must remain intact but you are applying the filter and modifying it every time, in the following example I show the correct way to do it

import sys
import cv2
import imutils
from PyQt5 import QtCore, QtGui, QtWidgets


class MyWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        ori_img = cv2.imread("../resources/omr-1-ans-ori.png", cv2.IMREAD_COLOR)
        self.original_image_color = imutils.resize(ori_img, height=960)
        self.original_image_gray = cv2.cvtColor(self.original_image_color, cv2.COLOR_BGR2GRAY)

        self.thresh = False
        self.thresh_karnel_size = 11

        self.init_ui()

    def init_ui(self):
        self.imglabel = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
        self.imglabel.setFixedSize(1200, 900)

        cb_thresh = QtWidgets.QCheckBox('thresh', checked=False)
        cb_thresh.stateChanged.connect(self.changeTitleThresh)

        self.thresh_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal, 
            focusPolicy=QtCore.Qt.StrongFocus,
            tickPosition=QtWidgets.QSlider.TicksBothSides,
            tickInterval=1,
            singleStep=1,
            pageStep=1,
            minimum=1,
            maximum=127)
        self.thresh_slider.valueChanged[int].connect(self.threshSliderChangeValue)

        vbox = QtWidgets.QVBoxLayout(self)
        vbox.addWidget(cb_thresh)
        vbox.addWidget(self.thresh_slider)
        vbox.addWidget(self.imglabel)
        self.threshSliderChangeValue(self.thresh_slider.value())
        self.setGeometry(50, 50, 1200, 768)
        self.setWindowTitle('Learning PyQT5')
        self.show()

    @QtCore.pyqtSlot(int)
    def changeTitleThresh(self, state):
        self.thresh = state == QtCore.Qt.Checked
        self.threshSliderChangeValue(self.thresh_slider.value())

    @QtCore.pyqtSlot(int)
    def threshSliderChangeValue(self, value):
        ksize = (value * 2) + 1
        if ksize > 1 and ksize % 2 != 0 and self.thresh:
            self.thresh_karnel_size = ksize
            _, gray_img = cv2.threshold(self.original_image_gray, self.thresh_karnel_size, 255, cv2.THRESH_BINARY)
            gray_img_c = cv2.cvtColor(gray_img.copy(), cv2.COLOR_GRAY2BGR)
            self.updateImage(gray_img_c)
        else:
            self.updateImage(self.original_image_color)

    def updateImage(self, image):
        height, width, channel = image.shape
        bytesPerLine = 3 * width
        qImg = QtGui.QImage(image.data, width, height, bytesPerLine, QtGui.QImage.Format_RGB888)
        pixMap = QtGui.QPixmap.fromImage(qImg).scaled(700, 500, QtCore.Qt.KeepAspectRatio)
        self.imglabel.setPixmap(pixMap)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ex = MyWindow()
    sys.exit(app.exec_())

Upvotes: 1

Related Questions