解决QLabel显示图片无法缩小问题的方法

    使用Qt编写界面显示OpenCV采集的图片时,如果使用QLabel作为图片显示控件,那么该控件的推荐最小尺寸(minimumSizeHint)就是图片的尺寸。这导致图片显示控件无法进一步压缩,在与其它控件一起布局时,缺乏灵活性。缩小窗口显示时,其它控件如表格、文本框都能等比例缩小,图片控件会一直保持原始尺寸。

    如下面的代码,对话框中内只显示一张图片。打印出的图片minimumnSizeHint为QSize(556, 222)。对话框无法压缩到比这个尺寸还小(给label设置QSizePolicy::Ignored,可以进一步缩小,但图片无法完整显示)。

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QDialog, QHBoxLayout, QLabel


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = QDialog()

    label = QLabel(dialog)
    label.setPixmap(QPixmap('picture.png'))
    label.setAlignment(Qt.AlignCenter)

    layout = QHBoxLayout(dialog)
    layout.addWidget(label)

    dialog.show()
    dialog.resize(480, 320)
    print(label.minimumSizeHint())
    sys.exit(app.exec_())

    运行结果显示对话框不能缩小显示。

解决方法:使用样式表显示图片

    使用样式表,将图片文件显示到控件背景上。这样图片就可以自由缩小了。

import sys
from PyQt5.QtWidgets import QApplication, QDialog, QHBoxLayout, QWidget


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = QDialog()

    widget = QWidget(dialog)
    widget.setStyleSheet('image:url(picture.png)')

    layout = QHBoxLayout(dialog)
    layout.addWidget(widget)

    dialog.show()
    dialog.resize(480, 320)
    print(widget.minimumSizeHint())
    sys.exit(app.exec_())

    注意,样式表中要属性要用image。属性使用border-image或background-image会有不同的效果(前者会调整图片铺满整个控件,后者会自动重复多张图片铺满整个控件)。

    运行效果如下。

解决方法二:使用paintEvent()自绘背景

    使用OpenCV采集的图像数据,有时候不会保存为文件,而是转换为QPixmap进行显示。要达到前面同样的效果,可以使用paintEvent()绘制到背景上。例子中作为对比,还是把图片用QPixmap载入后进行显示。MyWidget继承了QWidget的paintEvent,实现了背景的绘制。

import sys
from PyQt5.Qt import Qt, QPointF
from PyQt5.QtGui import QPixmap, QPainter, QPaintEvent
from PyQt5.QtWidgets import QApplication, QDialog, QHBoxLayout, QWidget


class MyWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

    def paintEvent(self, event: QPaintEvent):
        super().paintEvent(event)
        pixmap = QPixmap('picture.png')
        painter = QPainter(self)
        scale = min(self.width()/pixmap.width(), self.height()/pixmap.height(), 1.0)
        width = scale * pixmap.width()
        height = scale * pixmap.height()
        painter.drawPixmap(QPointF((self.width()-width)/2, (self.height()-height)/2),
                           pixmap.scaled(round(width), round(height), Qt.KeepAspectRatio, Qt.SmoothTransformation))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = QDialog()

    widget = MyWidget(dialog)

    layout = QHBoxLayout(dialog)
    layout.addWidget(widget)

    dialog.show()
    dialog.resize(480, 320)
    sys.exit(app.exec_())

    运行效果与方法二基本相同。

解决方法三:使用QGraphicsView的fitInView()

    方法二在绘制时,需要计算图片的缩小比例与绘制位置。而这些都可以能过QGraphicsView的fitInView()函数实现。我们可以写一个QGraphicsView派生类MyGraphicsView,并只包含一个QGraphicsPixmapItem项目用于显示图片。给MyGraphicsView添加一个判断是否需要缩小显示的函数view_resize()。它将判断控件大小无法完整显示图片时,使用fitInView()调节图片显示。 在用户改变控件尺寸或导入新图片时,调用view_resize()。

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QDialog, QHBoxLayout, QGraphicsPixmapItem, QGraphicsScene, QGraphicsView


class MyGraphicsView(QGraphicsView):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.image = QGraphicsPixmapItem()  # 创建Graphics图片对象
        self.image.setTransformationMode(Qt.SmoothTransformation)  # 图片平滑
        self.img_w = 0
        self.img_h = 0

        scene = QGraphicsScene(self)  # 创建Graphics场景
        scene.addItem(self.image)

        self.setScene(scene)  # Graphics视图初始化
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)  # 隐藏滚动条
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

    def resizeEvent(self, e):
        self.view_resize()
        super().resizeEvent(e)

    def view_resize(self):
        if self.img_w > self.width() or self.img_h > self.height():
            self.fitInView(self.image, Qt.KeepAspectRatio)

    def set_pixmap(self, pixmap: QPixmap):
        self.image.setPixmap(pixmap)
        self.img_w = pixmap.width()
        self.img_h = pixmap.height()
        self.view_resize()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = QDialog()

    widget = MyGraphicsView(dialog)
    widget.set_pixmap(QPixmap('picture.png'))
    layout = QHBoxLayout(dialog)
    layout.addWidget(widget)

    dialog.show()
    dialog.resize(480, 320)
    sys.exit(app.exec_())

    运行效果如下。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
您好!对于在Qt中使用OpenCV控件并在视频图像显示之前的问题,可以按照以下步骤进行操作: 1. 首先,确保已经正确地集成了Qt和OpenCV库到您的项目中。 2. 创建一个Qt窗口应用程序,并在UI设计中添加一个控件用于显示视频图像,例如一个QLabel。 3. 在您的代码中,使用OpenCV读取视频文件或者从摄像头捕获视频帧。 4. 将捕获到的视频帧转换为Qt图像格式,例如QImage。 5. 将转换后的图像设置给QLabel控件进行显示。 下面是一些示例代码,帮助您理解如何在Qt中实现这个功能: ```cpp #include <QApplication> #include <QLabel> #include <QTimer> #include <opencv2/opencv.hpp> int main(int argc, char *argv[]) { QApplication app(argc, argv); // 创建Qt窗口和控件 QLabel label; label.show(); cv::VideoCapture capture("path_to_video_file"); // 替换为您的视频文件路径或者摄像头索引 QTimer timer; QObject::connect(&timer, &QTimer::timeout, [&]() { cv::Mat frame; capture >> frame; if (!frame.empty()) { // 将OpenCV的Mat转换为Qt的QImage QImage image(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888); image = image.rgbSwapped(); // 如果图像是BGR格式,需要进行颜色通道交换 // 将图像设置给QLabel控件进行显示 label.setPixmap(QPixmap::fromImage(image).scaled(label.size(), Qt::KeepAspectRatio)); } }); // 设置定时器的时间间隔,控制视频帧的刷新率 timer.setInterval(33); // 30帧/秒 // 启动定时器 timer.start(); return app.exec(); } ``` 请注意,以上代码仅为示例,您需要根据您的实际需求进行调整和扩展。希望对您有帮助!如有任何问题,请随时提问。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值