zhilaanabdrsyd
zhilaanabdrsyd

Reputation: 1

How to draw rectangle to extract the ROI of a QImage displayed in a Qlabel widget

I've created a AnotherWidget window based on QWidget that contains a Qlabel and some other QLineEdit to show the X and Y Offset, also a Width and Height for the rectangle selection of the image.

The initial condition to met is to draw a rectangle over the image. Showing the image in a QLabel is successful, but when I draw the rectangle, it seems like it draws on the Widget window background. Here are few images to explain the situation.

The widget window that I've been working on:

this image

The current situation when drawing rectangle:

this situation image

The mouse event and painting event were fine, but it draws the rectangle on the background! (Weird, maybe i miss something when working with the Qlabel)

I kinda new with all this PyQt things, and currently using PySide6 in my VSCode environment. here's the code


class AnotherWidget(QWidget, Ui_ROIWidget):
    roi_selected = Signal(int,int,int,int)

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle("Custom ROI selection")
        self.begin = QPoint()
        self.end = QPoint()

    def paintEvent(self, event):
        super().paintEvent(event)

        qp = QPainter(self)
        br = QBrush(QColor(100, 10, 10, 40))  
        qp.setBrush(br)   
        qp.drawRect(QRect(self.begin, self.end))       

    def mousePressEvent(self, event):
        self.begin = event.pos()
        self.end = event.pos()
        self.update()

    def mouseMoveEvent(self, event):
        self.end = event.pos()
        self.update()

    def mouseReleaseEvent(self, event):
        self.begin = event.pos()
        self.end = event.pos()
        self.rect = QRect(self.start_point, self.end_point).normalized()
        self.update()
        x, y, width, height = self.rect.x(), self.rect.y(), self.rect.width(), self.rect.height()
        self.roi_selected.emit(x, y, width, height)
        self.update()

    @Slot()
    def show_image(self,image):
        self.label.setPixmap(QPixmap.fromImage(image))

What happened to this? is there something i miss on my method definition with the QPainter, or i should use another widget instead of Qlabel to display the image? what should i do?

EDIT assuming it might be needed, im using QtDesigner to adjust all the widget and mainwindow, and here I'm emitting ImageROI as a captured image signal from camera Thread to the main window method.


class CameraProccess(QThread):
    #Signal type definition 
    Image=Signal(QImage)
    ImageProcess = Signal(QImage)
    ImageCaptured = Signal(QImage)
    ImageROI = Signal(QImage)
    
    [...]

class mainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
       super().__init__()
        self.setupUi(self)
        self.setWindowTitle("Recorder Inspection Monitor V1.0")
        self.resize(1280,800)

        self.ROIwindow = AnotherWidget()
        self.setROIButton.clicked.connect(self.toggle_roiWindow)
 
    [...]
 
    def toggle_roiWindow(self):
        global setROI

        setROI = True

        if self.ROIwindow.isVisible()==False:
            self.Worker1_Opencv.ImageROI.connect(self.ROIwindow.show_image)
            self.ROIwindow.show()
        
        else:
            self.Worker1_Opencv.ImageROI.connect(self.ROIwindow.show_image)

Upvotes: 0

Views: 200

Answers (1)

Haru
Haru

Reputation: 2083

No. You should use QRubberBand class instead of paintEvent.

paintEvent draws on the widget itself (Exactly speaking, the widget as paintDevice.)

You put your image on the device, so you can't draw rectangle on the image. You have carelessly been drawing on the widget, so the image hides the rectangle.

Owing to no complete minimal sample code, I submit a demonstration for using QRubberband.

Please delete the codes of paintEvent.

You can get the information about how to use QRubberBand.

Qt Documentation - QRubberBand

PySide6:

from PySide6.QtWidgets import QWidget, QApplication, QRubberBand
from PySide6.QtGui import QPainter, QBrush, QColor, QPixmap
from PySide6.QtCore import Signal, Slot, QPoint, QRect

class AnotherWidget(QWidget ):
    roi_selected = Signal(int,int,int,int)

    def __init__(self):
        super().__init__()

        self.setWindowTitle("Custom ROI selection")
        self.begin = QPoint()
        self.end = QPoint()
        self.rubberBand = QRubberBand(QRubberBand.Shape.Rectangle, self)
    def paintEvent(self, event):
        super().paintEvent(event)
 

    def mousePressEvent(self, event):
        self.begin = event.position().toPoint()
        self.end = event.position().toPoint()
        rect = QRect()
        rect.setCoords(self.begin.x(), self.begin.y(), self.end.x(), self.end.y())
        self.rubberBand .setGeometry(rect)
        self.rubberBand.show()
  
        self.update()

    def mouseMoveEvent(self, event):
        self.end = event.position().toPoint()
        rect = QRect()
        rect.setCoords(self.begin.x(), self.begin.y(), self.end.x(), self.end.y())    
        self.rubberBand .setGeometry(rect)
        self.update()

    def mouseReleaseEvent(self, event):
        self.begin = event.position().toPoint()
        self.end = event.position().toPoint()
        rect = QRect()
        rect.setCoords(self.begin.x(), self.begin.y(), self.end.x(), self.end.y())
        self.rubberBand .setGeometry(rect)

        self.update()
        x, y, width, height = rect.x(), rect.y(), rect.width(), rect.height()
        self.roi_selected.emit(x, y, width, height)
        self.update()
        self.rubberBand.close()

    @Slot()
    def show_image(self,image):
        self.label.setPixmap(QPixmap.fromImage(image))

def main():
        import sys
        app = QApplication()
        w = AnotherWidget()
        w.show()
        sys.exit(app.exec())
        
if __name__ == "__main__":
    main()

Upvotes: 0

Related Questions