首页 > 其他分享 >震惊!!一男子用尽了各种方式都搜不到这个资源,于是他竟然将手伸向了......!?pyqt pyside 随窗口自适应、可缩放、拖动QLabel

震惊!!一男子用尽了各种方式都搜不到这个资源,于是他竟然将手伸向了......!?pyqt pyside 随窗口自适应、可缩放、拖动QLabel

时间:2024-09-11 12:20:46浏览次数:12  
标签:scale img pyside 缩放 ...... height width image self

震惊!!一男子用尽了各种方式都搜不到这个资源,于是他竟然将手伸向了......!?pyqt pyside 随窗口自适应、可缩放、拖动QLabel

需求场景

在小才玩yolo目标检测时,总是使用PyQt或PySide来展示识别结果。一开始小才使用自带的QLabel来显示图像,但是发现显示的比较呆,原QLabel显示有以下特点:

 1. 窗口大小改变时,QLabel图片显示不会跟随窗口变化。
 2. 图片不能够缩放,拖动。

于是小才就去搜索学习,许久后,总结加拓展自己实现了一个 随窗口自适应、可缩放、拖动、画框图片的自定义QLabel类(嘲笑请偷偷)。
实现效果:
演示

实现

不废话直接上代码

import cv2
from PySide6.QtCore import QPoint, Qt, QRect
from PySide6.QtCore import Signal
from PySide6.QtGui import QPainter, QPixmap, QImage, QMouseEvent, QKeyEvent, QPen, QColor
from PySide6.QtWidgets import QLabel
from check_except import check_except

class ImageLabel(QLabel):
    clicked_signal = Signal()
    # clicked_signal = pyqtSignal()# pyqt5

    # 当画框完成后向外输出信号 index: 0原图 1 裁剪后的图片 [2-5裁剪范围]2:x1 3:y1 4:width 5:height
    bbox_down_signal = Signal(list)

    def __init__(self, parent, scale_flag=True, move_flag=True, is_original=False, draw_bbox_flag=False):
        super(ImageLabel, self).__init__(parent)
        '''
        @param parent: 父控件
        @param scale_flag: 是否可以缩放
        @param move_flag: 是否可以移动
        @param is_original: 是否为原图
        @param draw_bbox_flag: 是否开启画框
        '''
        self.scaled_img = None # QPixmap
        self.cv_image = None  # draw_bbox_flag=True 时,为cv2原图
        self.point = None # 图片位置
        self.start_pos = None # 鼠标按下时的位置
        self.end_pos = None # 鼠标松开时的位置
        self.right_press = False # 右键正在按压
        self.left_press = False  # 左键正在按压
        self.is_original = is_original # 是否为原图显示
        self.x_scale = 1
        self.y_scale = 1

        # 画框起始点
        self.bbox_start_point = None
        # 画框结束点
        self.bbox_end_point = None

        # 是否可以缩放 scale_flag True 可以缩放
        self.scale_flag = scale_flag
        # 是否可以移动
        self.move_flag = move_flag

        # 是否开启画框
        self.draw_bbox_flag = draw_bbox_flag

    @check_except()
    def clear_image(self):
        self.set_q_pixmap(QPixmap(None))

    @check_except()
    def to_q_image(self, image):
        label_size = (self.height(), self.width())
        height, width = image.shape[:2]
        if not self.is_original:
            n_height = label_size[0]
            n_width = int((width / height) * label_size[0])
            if n_width > label_size[1]:
                n_width = label_size[1]
                n_height = int((height / width) * label_size[1])
            image = cv2.resize(image, (n_width, n_height))
        else:
            n_height = height
            n_width = width
        channels = len(image.shape)
        if channels == 2:
            bytes_per_line = n_width
            q_image = QImage(image.data, n_width, n_height, bytes_per_line, QImage.Format_Grayscale8)
        else:
            bytes_per_line = 3 * n_width
            q_image = QImage(image.data, n_width, n_height, bytes_per_line, QImage.Format_RGB888).rgbSwapped()
        return q_image

    @check_except()
    def set_cv_image(self, img):
        self.set_q_image(self.to_q_image(img))

    @check_except()
    def set_q_image(self, img):
        self.set_q_pixmap(QPixmap.fromImage(img))

    @check_except()
    def set_q_pixmap(self, q_pixmap):
        self.scaled_img = q_pixmap
        if self.point is None:
            self._reset_scale()
            self._reset_point()

        self.update()

    def _reset_scale(self):
        if self.scaled_img:
            self.x_scale = self.width() / self.scaled_img.width()
            b = self.scaled_img.height() / self.scaled_img.width()
            n_height = self.width() * b
            if n_height > self.height():
                self.y_scale = self.height() / self.scaled_img.height()
                self.x_scale = self.y_scale
            else:
                self.y_scale = self.x_scale
            self.reset_bbox()

    def _reset_point(self):
        if self.scaled_img:
            width, height = self.scaled_img.width(), self.scaled_img.height()
            p1 = 0
            p2 = 0
            if self.width() > width * self.x_scale:
                p1 = int((self.width() - width * self.x_scale) / 2)
            if self.height() > height * self.y_scale:
                p2 = int((self.height() - height * self.x_scale) / 2)
            self.point = QPoint(int(p1 / self.x_scale) if self.x_scale != 0 else 0,
                                int(p2 / self.y_scale) if self.y_scale != 0 else 0)
            # 重置框
            self.reset_bbox()

    def reset_bbox(self):
        self.bbox_start_point = None
        self.bbox_end_point = None

    @check_except()
    def paintEvent(self, e):
        if self.scaled_img:
            painter = QPainter()
            painter.begin(self)
            painter.scale(self.x_scale, self.y_scale)
            painter.drawPixmap(self.point, self.scaled_img)  # 此函数中还会用scale对point进行处理
            if self.draw_bbox_flag and self.bbox_start_point is not None and self.bbox_end_point is not None:
                lw = max(round(sum(self.cv_image.shape) / 2 * 0.003)

标签:scale,img,pyside,缩放,......,height,width,image,self
From: https://blog.csdn.net/hz1hz/article/details/142124134

相关文章

  • PyQt6/PySide6:账本项目前端制作【附完整项目地址】
    0.前言最近在家里闲着没事,正好又看到朋友@studentWheat发了篇用Tkinter做的账本,于是决定跟他一起改进这个程序。屏幕截图:1.后端后端主要是朋友做的,在这里就不多说了,放个代码:src/api.pyfromcollectionsimportdefaultdictclassApiError(RuntimeError):passd......
  • 记录 PyQt6 / PySide 6 自定义边框窗口的 Bug 及可能可行的解决方案:窗口抖动和添加 DW
    前言:本篇文章将要讨论我在前不久发表的关于PyQt6/PySide6自定义边框窗口代码及内容中的问题:(终)PyQt6/PySide6+Pywin32自定义标题栏窗口+完全还原Windows原生窗口边框特效_pyside6win32无边框窗口-CSDN博客https://blog.csdn.net/2402_84665876/article/detail......
  • 解决WinForm程序在高DPI屏幕下界面缩放错误
    在高DPI设置下,WinForm应用程序的界面可能会出现扭曲或缩放不正确的问题。这是因为默认情况下,WinForm的布局和控件尺寸是基于标准DPI设计的,当在高DPI环境下运行时,界面可能会被强制缩放,导致控件排列不正确或模糊。要解决这个问题,你可以尝试以下几种方法:1.启用DPI感知(DPI......
  • IO进程练习:请在linux 利用c语言编程实现两个线程按照顺序依次输出”ABABABAB......“
    例如:a线程输出”A”之后b线程输出”B”,然后a线程输出“A”,再b线程输出”B”,之后往复循环。【1】使用信号量实现代码展示:#include<stdio.h>#include<pthread.h>#include<string.h>#include<semaphore.h>#include<unistd.h>//定义两个全局信号量,实现同步机制se......
  • 程序员金九银十面试宝典(持续更新中................)
    大家好,我是一位老程序员,分享大家的一路关注的,很久没有更新了,今年大家都很不容易,这里有一份多年来整理的一份Java,大模型,项目管理,Mac软件等各类学习资料及面试题,无论你刚入行的程序员,还是经验丰富IT人士,希望这些资料能帮到你。让我们乘风破浪,顺利拿到理想offer!其它资料在陆陆续续......
  • swiper缩放图
    swiper缩放图Swiper中文网-轮播图幻灯片js插件,H5页面前端开发分为大图和小图,就是主图和缩略图(class里面可以有不止一个属性)需要把自己的图片插入相应位置(上图我已经插入了六个演示图片),在swiper-slide里面,格式可以在swiper官网粘贴相应的:如果需要添加轮播组件,需要在相......
  • 解决方案 | IrfanView如何滑动滚轮图像缩放?
    这是个bug,已经很多人反映了。目前没有比较好的解决方法,还是使用ctrl+滚轮最好。如果需要设置滚轮放大的话,按照下图即可,但是带来一个bug,你无法通过方向键或者菜单的箭头浏览下一张图片。综上所述,你有3个选择,1接受使用ctrl+滚轮进行放大2设置--关闭”显示所有支持的文件/缩略图......
  • 基于PySide6的串口组手
    目录一、软件界面二、各部分详情1、串口设置2、显示设置3、发送区设置4、接收区设置5、各部分统一一、软件界面如图所示,主要由串口设置、显示设置、发送区、接收区四部分组成:二、各部分详情1、串口设置设置串口、波特率、数据位、停止位、数据位、停止位、校......
  • PyQt5 / PySide 2 + Pywin32 自定义标题栏窗口 + 还原 Windows 原生窗口边框特效(2)
    前言:已修复上一篇文章中提到的Bug,增加状态切换动画:PyQt5/PySide2+Pywin32自定义标题栏窗口+还原Windows原生窗口边框特效-CSDN博客https://blog.csdn.net/2402_84665876/article/details/141487635?spm=1001.2014.3001.5501仍然存在的问题:打开窗口时窗口标题栏......
  • PyQt5 / PySide 2 + Pywin32 自定义标题栏窗口 + 还原 Windows 原生窗口边框特效
    Bug:当窗口不处于顶层时,如果点击窗体试图将其置于顶层,窗体自带的白边框会突然显示,最长两秒。完整性:尚未添加窗口状态的过渡动画和淡入、淡出动画。其他问题:由于Qt官方在版本6去掉了QtWin,目前暂未找到PyQt6/PySide6的解决方案。准备工作:在同目录下放四张照片:m......